Как правильно написать условие в сигнале 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)