Как правильно написать условие в сигнале pre_save в Django

Я только начал свою карьеру в IT как джуниор с Python/Django. В настоящее время я работаю над складской/инвентарной частью нашего магазина на бэкенде Python/Django.

Я хочу сделать так, чтобы при изменении

на quantity в Item (это две разные модели - ItemModel - модель элемента в различных конфигурациях) происходило изменение ItemModel из Order.status в PAID (это две разные модели - ItemModel - модель элемента в различных конфигурациях) - как когда действие срабатывает от клиента после оформления заказа (например, банк подтверждает оплату), так и когда оно задается вручную в панели администратора. Поэтому я установил сигнал на функцию следующим образом:

@receiver(post_save, sender=Order)
def update_stock(sender, instance, created, **kwargs):
    status_values = [order.status for order in instance.status_history.all()]
    if instance.status == OrderStatus.PAID and instance.status not in status_values:
       stock_to_change = []
       # do something to change the stock quantity in loops
       # Take ItemModel.object -> create StockMove.object
И здесь начинается проблема:

Даже если Order создается впервые сразу со статусом PAID, он будет иметь значение PAID в своей истории статусов, потому что это post_save, поэтому только что созданный статус уже там. Вот что пришло мне в голову - хорошо, изменим второе условие на instance.status not in status_values[:1]. Но это не работает - потому что в указанном случае и в любом другом заказе с текущим статусом PAID он вернет список без значения PAID (которое является последним в списке), поэтому каждое изменение в заказе (например, новый адрес доставки) будет изменять количество заказанного товара на складе (оно должно обновляться только один раз, когда статус устанавливается на paid в первый раз aka. PAID != status_values).

Я потратил целый день на решение этой проблемы, но сдался. Должен ли я просто переопределить метод save() в order.model? Спасибо за любые советы!

Кажется, я нашел ответ, возможно, не очень красивый, но он работает так, как я хочу.

@receiver(post_save, sender=Order)
def update_stock(sender, instance, created, update_fields, **kwargs):
    status_values = [order.status for order in instance.status_history.all()]

    if instance.status == OrderStatus.PAID:
        if instance.status not in status_values[:-1]:
            if created or (update_fields is not None and 'status' in update_fields):
                stock_to_change = []

Чтобы работать, необходимо также переопределить save_model() в OrderAdmin:

@admin.register(models.Order)
class OrderAdmin(admin.ModelAdmin):
    
    ...

    def save_model(self, request, obj, form, change):
        update_fields = []

        if change: 
            if form.initial['status'] != form.cleaned_data['status']:
                update_fields.append('status')


        obj.save(update_fields=update_fields)
        return super(OrderAdmin, self).save_model(request, obj, form, change)
Вернуться на верх