Редактирование параллелизма в Django - PullRequest
0 голосов
/ 29 апреля 2018

Я немного запутался в том, как и где должны быть реализованы мои функции редактирования параллелизма, чтобы нельзя было выполнить редактирование параллелизма Mutex. Мой код:

models.py

class Order(models.Model):
    edit_version = models.IntegerField(default=0, editable=True) # For concurrency editing 

    ### Added for concurrency with 2 or more users wanting to edit the same form ###
    locked = models.BooleanField(default = False)
    def lock_edit(self):
        self.locked = True
        print ("locked_1: {0}".format(self.locked)) #Test purposes only
        super().save() # what's this doing exctly??

    def save_edit(self):
        self.locked = False
        print ("locked_2: {0}".format(self.locked)) #Test purposes only
        super().save()

view.py

@permission_required('myapp.edit_order', fn=objectgetter(Order, 'id'))
def edit_order(request,id = None):
    """
    """
    order = Order.objects.get(id=id)
    print ("order: {0}".format(order))
    print ("EDIT_VERSION: {0}".format(order.edit_version))

    if settings.USE_LOCKS:
        print("order.locked: {0}".format(order.locked))
        order.lock_edit()
        #order.locked = False # only to force the else clause for testing
        if order.locked:
            print ("Editing this form is prohibited because another user has already locked it.")
            messages.info(request, 'Editing this form is prohibited because another user has already locked it.') # TODO: Pop-up and redirect necessary
            return HttpResponseRedirect('/sanorder')
            #raise ConcurrencyEditUpdateError #Define this somewhere
        else:
            print ("Order lock is False")
            order.lock_edit()
            print("order.locked_new: {0}".format(order.locked))
            updated = Order.objects.filter(edit_version=order.edit_version).update(edit_version=order.edit_version+1)
            print ("UPDATED: {0}".format(updated))
            print ("EDIT_VERSION_NEW: {0}".format(order.edit_version))
            #return Order.objects.filter(edit_version=order.edit_version).update(edit_version=order.edit_version+1)
            return updated > 0



        ### Here are further functions in the form executed ###


        if updated > 0: # For concurrency editing
        order.save_edit()

    return render(request, 'myapp/order_edit.html',
        {'order':order,
            'STATUS_CHOICES_ALREADY_REVIEWED': dSTATUS_CHOICES_ALREADY_REVIEWED,
            'bolError': bolError,
            'formQuorum': formQuorum,
            'formCustomer': formCustomer,
            'formInfo': formInfo,

        })

Предполагается, что пользователь может получить доступ и редактировать определенную форму, но только если никто не редактирует ее. В противном случае пользователь видит всплывающее сообщение и перенаправляется на главную страницу. Когда пользователь редактирует, блокировка срабатывает и снимается при отправке формы. В данном случае это относится к строкам:

    if updated > 0: # For concurrency editing
    order.save_edit()

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

1 Ответ

0 голосов
/ 08 мая 2018

Основная проблема, которую я вижу в вашем коде, заключается в том, что кроме сохранения - вы, кажется, нигде не снимаете блокировку (также я думаю, что ваш отступ нарушен в исходном сообщении, но это не имеет значения, так как Я мог догадаться о намерении).

Для того, чтобы правильно реализовать блокировку, 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, который будет постоянно (например, каждую минуту) блокировать издание заказа, что должно держать заказ заблокированным до тех пор, пока человек запертый закрывает свою вкладку. В качестве альтернативы (вероятно, лучше, чем вышеописанное) было бы предупредить пользователя о том, что срок действия его блокировки истекает, и если он хочет продлить ее - это ваше дело.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...