Основная проблема, которую я вижу в вашем коде, заключается в том, что кроме сохранения - вы, кажется, нигде не снимаете блокировку (также я думаю, что ваш отступ нарушен в исходном сообщении, но это не имеет значения, так как Я мог догадаться о намерении).
Для того, чтобы правильно реализовать блокировку, IMO необходимо иметь примечание по крайней мере о следующем:
- Кто заблокировал экземпляр модели
- Когда истекает срок блокировки
Общая идея о том, как будет работать блокировка в этом случае, будет:
- Если вы первый пользователь, запустивший издание - заблокируйте экземпляр модели
- Если вы владелец блокировки, вы можете редактировать блокировку (это на тот случай, если оригинальный редактор случайно закроет вкладку и захочет продолжить редактирование снова)
- Если вы не являетесь владельцем замка И срок действия блокировки еще не истек, вы не можете редактировать модель
- Если вы не владелец блокировки, НО срок действия блокировки истек, вы можете отредактировать ее (теперь вы владелец блокировки).
Итак, псевдо-реализация будет выглядеть следующим образом:
Модель:
class Order(models.Model):
LOCK_EXPIRE = datetime.timedelta(minutes=3)
locked_by = models.ForeignKey(User, null=True, blank=True)
lock_expires = models.DateTimeField(null=True, blank=True)
def lock(self, user):
self.locked_by = user
self.lock_expires = datetime.datetime.now() + self.LOCK_EXPIRE
self.save()
def unlock(self):
self.locked_by = None
self.lock_expires = None
self.save()
def can_edit(self, user):
return self.locked_by == user or self.lock_expires < datetime.datetime.now()
Вид:
def edit_order(request, order_id = None):
with transaction.atomic():
# get_object_or_404 is just to avoid redundant '404' handling
# .select_for_update() should put a database lock on that particular
# row, preventing a race condition from happening
order = get_object_or_404(Order.objects.select_for_update(), id=order_id)
if not order.can_edit(request.user):
raise Http403
order.lock(request.user)
# Handle form logic
order.unlock()
order.save()
Для дальнейшего улучшения вы можете создать простую конечную точку блокировки и разместить на своем веб-сайте код JavaScript, который будет постоянно (например, каждую минуту) блокировать издание заказа, что должно держать заказ заблокированным до тех пор, пока человек запертый закрывает свою вкладку. В качестве альтернативы (вероятно, лучше, чем вышеописанное) было бы предупредить пользователя о том, что срок действия его блокировки истекает, и если он хочет продлить ее - это ваше дело.