1. Iakov Davydov

    30.01.2009

    0 ↑
    0 ↓
    Наверняка такое уже обсуждалось, но не могу придумать, по каким ключевым словам искать.

    Допустим у нас есть некий вопрос.
    class Question(models.Model):
    text = ...
    Ответы мы принимаем до тех пор, пока не определимся с правильным ответом.

    Например:
    class UnapprovedAnswer(models.Model):
    question = models.ForeignKey(Question)
    text = ...
    и
    class ApprovedAnswer(models.Model):
    question = models.ForeignKey(Question, unique=True)
    text = ...
    Мы должны выбрать UnapprovedAnswer и создать на его основе ApprovedAnswer. При этом все UnapprovedAnswer к этому Question нужно удалить.

    Как это сделать и быть уверенным, что праллельно у нас не появился новых ответов? Или иными словами как атомарно проверить отсутствие ApprovedAnswer и создать UnapprovedAnswer?

    Спасибо.

    P.S. Модели не обязательно таким образом должны быть построены. Главное — идея.
  2. Вас спасут два BooleanField:-)

    1. Очевидно, что такая модель ответов концептуально некрасива. Ответ дожен быть представлен одной моделью с пометкой, какой из множества для вопроса верен.

    2. Нужно блокировать вопрос при поступлении правильного ответа. Поэтому ему тоже флажок повесить.

  3. Iakov Davydov

    30.01.2009

    0 ↑
    0 ↓
    Александр, мне кажется таким образом мы просто меняем один race condition на другой. Флажки же тоже нужно успевать проверять/проставлять.

    Можно вас попросить привести более конкретный пример?
  4. Средставами ORM невозможно заблокировать выбранные строки для последующего изменения (как в некоторых СУБД например произходит при SELECT FOR UPDATE).

    Следовательно, вы маркируете каждый ответ временем создания, при поступлении правильного, отмечаете вопрос как решенный и берете самый старый из правильных ответов(если не повезло и их несколько).

    Или просто опускаетесь до raw sql и делатет блокировку.

  5. ziro

    31.01.2009

    0 ↑
    0 ↓
    Мне кажется, что здесь надо использовать версионность. То есть к вопросу добавить поле версии типа интежер и инкрементировать его при поступлении каждого нового ответа. Далее применить http://softwaremaniacs.org/blog/2009/01/14/changed-data-in-forms/ - это поможет определить есть ли новые ответы или нет. Возможно в модель надо добавить флаг approved, чтобы нельзя было добавлять новые ответы. Хотя в этом случае проблема с блокировкой остается, но ее можно победить у Ивана было написано про блокировку на основе файлов.
  6. ziro

    31.01.2009

    0 ↑
    0 ↓
    Извиняюсь:
    >Возможно в модель надо добавить флаг approved
    читать как:
    Возможно в модель вопроса надо добавить флаг approved
  7. Иван Сагалаев

    31.01.2009

    0 ↑
    0 ↓

    Хотя в этом случае проблема с блокировкой остается, но ее можно победить у Ивана было написано про блокировку на основе файлов.

    На самом деле, select for update попроще. Например не надо думать про освобождение лока, он снимается с завершением транзакции.

  8. Iakov Davydov

    01.02.2009

    0 ↑
    0 ↓
    А select for update в django есть?
  9. Иван Сагалаев

    01.02.2009

    0 ↑
    0 ↓

    В ORM пока нет. Но ничто не мешает сделать его вручную:

    from django.db import connection
    
    cursor = connection.cursor()
    cursor.execute('begin')
    cursor.execute('select 1 from some_table where id = %s for update', [id])
    
  10. Если уж делать как предлагает Ваня - то в кастомном менеджере с выбором имени таблицы и primary key поля.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.