Django信号-通过django管理员更新模型时,kwargs ['update_fields']始终为None [英] Django signals - kwargs['update_fields'] is always None on model update via django admin

查看:247
本文介绍了Django信号-通过django管理员更新模型时,kwargs ['update_fields']始终为None的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的django应用程序内部有一个信号,我想检查模型中的某个字段是否已更新,因此我可以继续进行操作。

I have a signal inside my django app where I would like to check if a certain field in my model has been updated, so I can then proceed and do something.

我的模型看起来像这样...

My model looks like this...

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.PositiveIntegerField()
    tax_rate = models.PositiveIntegerField()
    display_price = models.PositiveInteger()
    inputed_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL)

我的信号看起来像这样...

My signal looks like this...

@receiver(post_save, sender=Product)
def update_model(sender, **kwargs):
    instance = kwargs['instance']
    if 'tax_rate' in kwargs['update_fields']:
        # do something

这将返回错误 None 不可迭代。我已经阅读了有关 update_fields 的django信号文档,上面写着传递给Model.save()的要更新的字段集;如果没有,我没有提到update_fields传递给save()。

This returns the error None is not an iterable. I have read the django signal documentation regarding the update_fields and it says The set of fields to update as passed to Model.save(), or None if update_fields wasn’t passed to save().

我应该提到我在django管理员内部工作,所以我希望会发生,我可以在django admin中创建我的产品模型的实例,然后再更新tax_rate或price的值时,可以检查它们并相应地更新 list_price 。但是, kwargs ['update_fields'] 始终返回None。
我怎么了?还是我可以在django管理员中实现该结果的其他方法?

I should mention that I am working inside django admin here so what I hoped would happen is, I could create an instance of my Product model in django admin and then later if the value of tax_rate or price were updated, I could check for those and update the list_price accordingly. However, kwargs['update_fields'] always returns None. What am I getting wrong? Or is there some other way I could achieve that result inside django admin?

更新的部分

现在,假设我在产品模型中引入了一个名为 inputed_by 的字段,该字段指向用户模型,我希望在首次保存模型时填充该字段。然后,另一个字段 updated_by 存储上次更新模型的用户。同时,我想检查 tax_rate price 中的一个或两个是否都已更新。

Now, say I introduce a field called inputed_by in my product model, that points to the user model and I want that field populated when the model is first saved. Then another field updated_by that stores the user who last updated the model. At the same time I wish to check whether either or both the tax_rate or price has been updated.

在模型管理员内部,我有以下方法...

Inside my model admin I have the following method...

def save_model(self, request, obj, form, change):
    update_fields = []
    if not obj.pk:
        obj.inputed_by = request.user
    elif change:
        obj.updated_by = request.user

        if form.initial['tax_rate'] != form.cleaned_data['tax_rate']:
            update_fields.append('tax_rate')
        if form.initial['price'] != form.cleaned_data['price']:
            update_fields.append('price')

    obj.save(update_fields=update_fields)
    super().save_model(request, obj, form, change)

我的信号现在看起来像这样...

My signal now looks like this...

@receiver(post_save, sender=Product, dispatch_uid="update_display_price")
def update_display_price(sender, **kwargs):
    created = kwargs['created']
    instance = kwargs['instance']
    updated = kwargs['update_fields']
    checklist = ['tax_rate', 'price']

    # Prints out the frozenset containing the updated fields and then below that `The update_fields is None`

    print(f'The update_fields is {updated}')

    if created:
        instance.display_price = instance.price+instance.tax_rate
        instance.save()
    elif set(checklist).issubset(updated):
        instance.display_price = instance.price+instance.tax_rate
        instance.save() 

我得到了错误'NoneType'对象是不可迭代的
该错误似乎来自 set(checklist)行。 issubset(已更新)。我尝试过专门在python shell内运行该行,它会产生所需的结果。这次出了什么事?

I get the error 'NoneType' object is not iterable The error seems to come from the line set(checklist).issubset(updated). I've tried running that line specifically inside the python shell and it yields the desired results. What's wrong this time?

推荐答案

应将字段集传递给 Model.save()使其在 update_fields 中可用。

The set of fields should be passed to Model.save() to make them available in update_fields.

像这样

model.save(update_fields=['tax_rate'])

如果您是通过django管理员创建的,并且总是,则表示 update_fields 尚未传递给模型的 save 方法。因此,它将始终为

If you are creating something from django admin and getting always None it means that update_fields has not been passed to model's save method. And because of that it will always be None.

如果您选中 ModelAdmin 类和 save_model 方法,您会发现调用是在没有 update_fields 关键字参数的情况下发生的。

If you check ModelAdmin class and save_model method you'll see that call happens without update_fields keyword argument.

如果您自己编写 save_model

以下代码将解决您的问题:

The code below will solve your problem:

class ProductAdmin(admin.ModelAdmin):
    ...
    def save_model(self, request, obj, form, change):
        update_fields = []

        # True if something changed in model
        # Note that change is False at the very first time
        if change: 
            if form.initial['tax_rate'] != form.cleaned_data['tax_rate']:
                update_fields.append('tax_rate')

        obj.save(update_fields=update_fields)

现在您可以测试成员资格了在 update_model 中。

Now you'll be able to test memberships in update_model.

这篇关于Django信号-通过django管理员更新模型时,kwargs ['update_fields']始终为None的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆