30.01.2009 20:15

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

    Допустим у нас есть некий вопрос.

    
    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. Александр, мне кажется таким образом мы просто меняем один race condition на другой. Флажки же тоже нужно успевать проверять/проставлять.

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

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

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

  5. ziro

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

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

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

  8. А select for update в django есть?
  9. В 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 поля.

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