简体   繁体   English

如何在 Django 的 pre_save 信号中写入正确的条件

[英]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.我刚刚开始了我的 IT 职业生涯,作为一名 Python/Django 的大三学生。 Currently I'm working on a stock/inventory part of our shop in Python/Django backend.目前,我正在 Python/Django 后端处理我们商店的库存/库存部分。

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.我想要做的是在将 Order.status 更改为PAID时更改ItemModel中的Item quantity (这是两个不同的模型 - ItemModel 是各种配置中的项目的Order.status ) - 当客户端触发操作时下订单后(例如银行确认付款)以及在管理面板中手动设置时。 So I set the signal on a function like this:所以我在 function 上设置信号,如下所示:

@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.即使Order是第一次以 PAID 状态创建的,它的状态历史记录中也会有 PAID 值,因为它是 post_save,所以刚刚创建的状态已经在那里。 So what came to my mind was - ok, change the second condition to instance.status not in status_values[:1] .所以我想到的是-好的,将第二个条件更改为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 ).但它不起作用 - 因为在上述情况下以及在任何其他具有当前 PAID 状态的订单中,它将返回一个没有 PAID 值的列表(这是列表中的最后一个),因此订单的每次更改(例如新的送货地址)都会改变库存数量订购的产品(它应该只在状态设置为第一次付款时更新一次PAID != status_values )。

I have spend whole day to solve this, but I gave up.我花了一整天的时间来解决这个问题,但我放弃了。 Should I just override save() method in order.model?我应该在 order.model 中覆盖 save() 方法吗? 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 :要工作,它还需要覆盖 OrderAdmin 中的OrderAdmin save_model()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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