从数据库重新加载Django对象


160

是否可以从数据库刷新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事务提交。为什么这样 您要等多久才能进行下一笔交易?
S.Lott 2010年

这似乎是不必要的功能。可以只从数据库中重新查找对象。
斯蒂芬,2010年

我想这是很好的,但它已被关闭多次在这里
eruciform

2
这是不合适的,因为Django模型对象是代理。如果将同一表行分为两个对象-x1 = X.objects.get(id = 1); x2 = X.objects.get(id = 1),它们将被测试为相等,但是它们是不同的对象,并且不共享状态。您可以分别更改和保存它们-最后保存的一个决定数据库中行的状态。因此,通过简单的分配-x1 = X.objects.get(id = 1)重新加载是正确的。拥有一个重载方法会导致许多人错误地推断x1.f ='new value'; (x1.f == x2.f)为True。
Paul Whipp 2014年

Answers:


259

从Django 1.8开始,内置了刷新对象。链接到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,最好选择其他答案之一。
蒂姆·弗莱彻

1
不确定docs中提到的“更新所有非延迟字段”是什么意思?
云提2015年

1
@Yunti您可以推迟字段,或显式地请求字段的子集,并且将仅部分填充结果对象。refresh_from_db只会更新此类已填充的字段。
301_Moved_Permanently

在文档中找不到详细信息,但是DoesNotExist如果在调用时删除了基础对象,则会适当地引发异常refresh_from_db。仅供参考。
Tim Tisdall

28

我发现从数据库中重新加载对象相对容易,如下所示:

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

19
是的,但是...之后,您必须更新对该对象的所有引用。不太方便且容易出错。
grep

2
当Celery在django之外的db中更新我的对象时,发现这是必要的,django显然保留了该对象的缓存,因为它不知道它已更改。
鲍勃·斯普林

3
从django.db.models.loading导入get_model; 实例= get_model(instance).objects.get(pk = instance.pk)
Erik

1
@grep仅仅花了2个小时为该用例编写测试:1:初始化模型;2:通过表单更新模型;3:测试新值是否已更新。...是的,容易出错。
vlad-ardelean 2014年

3
我认为refresh_from_db解决了所有这些问题。
Flimm

16

在引用@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

感谢您的解决方案。如果只允许多次投票!
user590028 2013年

11
Django现在提供了refresh_from_db方法。
Flimm

9

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

foo.refresh_from_db()

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.