在 Django 模型中使用 update() 时如何跟踪更改

How to track changes when using update() in Django models

我试图在字段更改时跟踪更改。

每当我使用 .save() 方法时,我都可以在 Django 管理历史记录中看到更改,但是每当我使用 .update() 方法时,它都不会记录我在对象中所做的任何更改。

我想使用 update() 因为它可以同时更改多个字段。它使代码更简洁、更高效(一次查询,一行...)

现在我正在使用这个:

u = Userlist.objects.filter(username=user['username']).update(**user)

我可以看到所有的变化

u = Userlist.objects.get(username=user['username'])
u.lastname=lastname
u.save()

我也在使用 django-simple-history 查看 changes.setup。

来自docs

Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save())

update() 在数据库级别工作,因此当通过 .update(...).

应用更新时,Django 管理员无法跟踪更改

如果您仍想跟踪更新的变化,您可以使用:

for user in Userlist.objects.filter(age__gt=40):
    user.lastname = 'new name'
    user.save()

然而,这更昂贵,如果唯一的好处是通过管理历史跟踪更改,则不建议这样做。

这是我处理这个问题的方法,到目前为止效果很好:

# get current model instance to update
instance = UserList.objects.get(username=username)

# use model_to_dict to convert object to dict (imported from django.forms.models import model_to_dict)
obj_dict = model_to_dict(instance)

# create instance of the model with this old data but do not save it
old_instance = UserList(**obj_dict)

# update the model instance (there are multiple ways to do this)
UserList.objects.filter(username=username).update(**user) 

# get the updated object
updated_object = UserList.objects.get(id=id)

# get list of fields in the model class
my_model_fields = [field.name for field in cls._meta.get_fields()]

# get list of fields if they are different
differences = list(filter(lambda field: getattr(updated_object, field, None)!= getattr(old_instance, field, None), my_model_fields))

差异变量将为您提供两个实例之间不同的字段列表。我还发现添加我不想检查差异的模型字段很有帮助(例如,我们知道 updated_date 将始终更改,因此我们不需要跟踪它)。

skip_diff_fields = ['updated_date']

my_model_fields = []
for field in cls._meta.get_fields():
    if field.name not in skip_diff_fields:
        my_model_fields.append(field.name)