【问题标题】:Reload django object from database从数据库重新加载 django 对象
【发布时间】:2011-05-21 15:24:59
【问题描述】:

是否可以从数据库中刷新 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) 为真。

标签: python django django-models


【解决方案1】:

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

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

【讨论】:

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

参考@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

【讨论】:

  • 感谢您的解决方案。如果只有 SO 允许多次投票!
  • Django 现在提供refresh_from_db 方法。
【解决方案3】:

从 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 异常。仅供参考。
【解决方案4】:

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

foo.refresh_from_db()

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-27
    • 2013-05-31
    • 2019-03-13
    • 2022-08-05
    • 2020-07-20
    相关资源
    最近更新 更多