Предотвращение состояния гонки между проверкой уникальности и вставкой

У меня есть проект Django 1.7 beta 1 со стандартной формой регистрации пользователя.

Концептуально имеет смысл, если проверка формы завершится ошибкой, если имя пользователя уже занято. Однако проверка формы и сохранение успешно созданной пользовательской модели — это отдельные шаги, поэтому существует состояние гонки, при котором проверка может пройти, но фактическая user.save() может завершиться ошибкой с IntegrityError.

Я не понимаю, что произойдет, если и проверка формы, и шаг user.save() будут заключены в один и тот же блок transaction.atomic() — я предполагаю, что postgres не будет создавать никаких блокировок при чтении таблицы, чтобы проверить, существует ли строка, и, следовательно, транзакция вообще не предотвратит состояние гонки.

Предполагая, что это так, как лучше всего справиться с этим? Вот варианты, которые я пока рассматриваю:

  • Полностью пропустите проверку уникальности имени пользователя и просто ловите IntegrityError во время сохранения, добавляя в список ошибок формы вручную. Это пуленепробиваемое, но перемещает некоторую логику проверки за пределы определения формы.
  • Выполните как этап проверки, так и блок try/except вокруг IntegrityError. Это может привести к дублированию кода, но теперь форма работает изолированно, и использование формы в представлении не вызывает состояния гонки.

person Andrew Gorcester    schedule 24.03.2014    source источник
comment
Не очень элегантно или что-то в этом роде, но вы могли бы создать объект в form.clean(), а затем убедиться, что вы заполняете эту модель, а не создаете новую при сохранении. Но это противоречит цели всего рабочего процесса формы и снова не полностью защищено от состояния гонки, поэтому я очень заинтересован в лучших ответах!   -  person frnhr    schedule 25.03.2014
comment
Это выглядит как форма вставки, если-не-существует, и имеет те же проблемы: его нельзя сделать свободным от гонок без возможности установить предикатную блокировку на несуществующую строку, чего PostgreSQL в настоящее время не может сделать. Таким образом, вы должны поймать ошибку целостности и справиться с ней так или иначе.   -  person Craig Ringer    schedule 25.03.2014