AFAIK Django没有提供通用方法来查看update_or_create()
是否更改了数据布尔值created
告诉我已经创建了一行。但是我怎么知道数据是否被更改(SQL UPDATE哪个更改了数据)
示例:
obj, created = MyModel.update_or_create(pk=12345,
defaults=dict(name='Doctor Zhivago'))
有三种情况:
obj
已创建。没问题,我有布尔变量created
obj
未创建,已更新。例如,之前的名字是" Machuca"。obj
未创建且未更新。例如,之前的名字已经是" Dr. Zhivago"。目前我无法区分case2和case3。
答案 0 :(得分:6)
感觉有点受@bakkal的启发,我编写了一个可以应用于自定义Manager类的mixin类,然后将该自定义Manager分配给MyModel
类。这会将返回的元组的格式更改为(obj, created, updated)
。在defaults.items()
中的值循环中,我正在检查是否有任何新值与旧值不同。
class UpdateOrCreateMixin(object):
def update_or_create_v2(self, defaults=None, **kwargs):
"""
Look up an object with the given kwargs, updating one with defaults
if it exists, otherwise create a new one.
Return a tuple (object, created, updated), where created and updated are
booleans specifying whether an object was created.
"""
defaults = defaults or {}
lookup, params = self._extract_model_params(defaults, **kwargs)
self._for_write = True
with transaction.atomic(using=self.db):
try:
obj = self.select_for_update().get(**lookup)
except self.model.DoesNotExist:
obj, created = self._create_object_from_params(lookup, params)
if created:
return obj, created, False
updated = False
for k, v in defaults.items():
oldattr = getattr(obj, k)
if oldattr != (v() if callable(v) else v):
updated = True
setattr(obj, k, v() if callable(v) else v)
obj.save(using=self.db)
return obj, False, updated
class CustomManager(UpdateOrCreateMixin, models.Manager):
pass
class MyModel(models.Model)
field = models.CharField(max_length=32)
objects = CustomManager()
obj, created, updated = MyModel.objects.update_or_create_v2(pk=12345,
defaults=dict(name='Doctor Zhivago'))
答案 1 :(得分:2)
考虑到如何实现该接口,如果对象已被创建,则无法判断该对象是否已更新。因为在这种情况下它始终会调用save()
。
以下是update_or_create()
目前的实施方式:
with transaction.atomic(using=self.db):
try:
obj = self.select_for_update().get(**lookup)
except self.model.DoesNotExist:
obj, created = self._create_object_from_params(lookup, params)
if created:
return obj, created
# [below part always runs the same if obj was not created]
for k, v in defaults.items():
setattr(obj, k, v() if callable(v) else v)
obj.save(using=self.db)
return obj, False
参考。 https://github.com/django/django/blob/master/django/db/models/query.py#L459
正如您所看到的,当没有创建对象时,它的实现方式无法判断它是否已更新。
但是,在调用save()
之前,您可以手动验证查找/更新值是否与数据库中现有对象的值不同,然后设置updated
标记。
答案 2 :(得分:0)
我目前正在使用混合方法来处理此类任务:
我没有last_edited
的模型上有last_modified
或auto_now=True
字段。
我使用django-dirtyfields而不是auto_now
方法而不是save
我做了类似的事情:
def save(*args, **kwargs):
if self.is_dirty():
self.last_modified = now()
super().save(*args, **kwargs)
如果您不喜欢save
方法中的混乱,可以使用pre_save
信号并根据脏字段更新last_modified
。
然后在调用update_or_create
之后,您可以非常安全地依赖last_modified
字段来检查模型是否确实已被修改。
dirtyfield的api非常简单,你可以在没有太多设置痛苦的情况下玩它。