ChatGPT解决这个技术问题 Extra ChatGPT

从数据库重新加载 django 对象

是否可以从数据库中刷新 django 对象的状态?我的意思是行为大致相当于:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

更新: 在跟踪器中发现重新打开/无法修复战争:http://code.djangoproject.com/ticket/901。仍然不明白为什么维护者不喜欢这个。

在普通的 SQL 上下文中,这是没有意义的。只有在您的事务完成并执行 commmit 之后 才能更改数据库对象。完成此操作后,您必须等待下一个 SQL 事务提交。为什么要这样做?你要等多久才能完成下一笔交易?
这似乎是一个不必要的功能;已经可以从数据库中重新查找对象。
我也想要这个,但它已被反复关闭here
这是不合适的,因为 Django 模型对象是代理。如果您将同一表行放入两个对象中 - x1 = X.objects.get(id=1); x2 = X.objects.get(id=1),它们将测试为相等但它们是不同的对象并且状态不共享。您可以独立更改并保存它们 - 最后一个保存的决定了数据库中行的状态。因此使用简单的赋值重新加载是正确的 - x1 = X.objects.get(id=1)。使用 reload 方法会导致许多人错误地推断 x1.f = 'new value'; (x1.f == x2.f) 为真。

T
Tim Fletcher

从 Django 1.8 开始,内置刷新对象。Link to docs

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@fcracker79 是的,它只在 1.8 中实现。对于早期版本的 Django,您最好选择其他答案之一。
不确定文档中提到的“所有非延迟字段都已更新”是什么意思?
@Yunti 您可以defer 个字段,或明确要求 only a subset 个字段,结果对象将仅被部分填充。 refresh_from_db 只会更新此类已填充的字段。
在文档中找不到详细信息,但如果在调用 refresh_from_db 时删除了基础对象,它会正确引发 DoesNotExist 异常。供参考。
A
Amandasaurus

我发现像这样reload the object from the database相对容易:

x = X.objects.get(id=x.id)

是的,但是...之后您必须更新对该对象的所有引用。不是很方便且容易出错。
当 Celery 在 django 之外的数据库中更新我的对象时,发现这是必要的,django 显然保留了该对象的缓存,因为它不知道它已经更改。
从 django.db.models.loading 导入 get_model; instance = get_model(instance).objects.get(pk=instance.pk)
@grep 刚刚浪费了 2 个小时来为这个用例编写测试:1:初始化模型; 2:通过Form更新模型; 3:测试新值是否已更新......所以是的,容易出错。
我认为 refresh_from_db 解决了所有这些问题。
R
Ron

正如@Flimm 指出的那样,这是一个非常棒的解决方案:

foo.refresh_from_db()

这会将数据库中的所有数据重新加载到对象中。


E
Eloff

参考@grep的评论,不应该这样做:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

感谢您的解决方案。如果只有这样允许多次投票!
Django 现在提供 refresh_from_db 方法。