简体   繁体   中英

How to write proper condition in pre_save signal in Django

I've just started my career in IT as a junior with Python/Django. Currently I'm working on a stock/inventory part of our shop in Python/Django backend.

What I want to do is to change quantity of Item in ItemModel (those are two different models - ItemModel is a model of an Item in various configuration) when Order.status is being change to PAID - both when the action is triggered by the client after order has been placed (eg the bank confirms the payment) and also when its set manually in the admin panel. So I set the signal on a function like this:

@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
And here starts the problem:

Even if Order is created for the first time at once with PAID status, it will have PAID value in its status history because it's post_save, so the status just created is already in there. So what came to my mind was - ok, change the second condition to instance.status not in status_values[:1] . But it doesnt work - because in mentioned case and in any other Order with current PAID status it will return a list without PAID value (which is last in the list), so every change in Order (eg new shipping address) will change stock quantity of ordered product (it should update it only once when the status is set to paid for the first time aka. PAID != status_values ).

I have spend whole day to solve this, but I gave up. Should I just override save() method in order.model? Thanks for any advices!

I think I've found the answer, maybe not a pretty one, but it works as I want.

@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()]

    # Do the rest of the code when Order with status PAID Created=True 
    # or order.status was updated to PAID value 
    # and PAID value is not in OrderStatusHistory.

    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 = []

To work it also needs to override an save_model() in 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM