Django模型reload_from_db()与从db显式调用

时间:2016-09-12 21:08:55

标签: python django django-models

如果我从模型中检索到对象,例如:

obj = Foo.objects.first()

我知道如果我想稍后引用此对象并确保它具有数据库中的当前值,我可以调用:

obj.refresh_from_db()

我的问题是,使用refresh_from_db()方法而不仅仅是做有什么好处吗?:

obj = Foo.objects.get(id=obj.id)

据我所知,结果将是相同的。 refresh_from_db()似乎更明确,但在某些情况下,它意味着额外的代码行。假设我更新了value的{​​{1}}字段,后来想要测试它已更新为obj。比较:

False

用这个:

obj = Foo.objects.first()
assert obj.value is True
# value of foo obj is updated somewhere to False and I want to test below
obj.refresh_from_db()
assert obj.value is False

我对讨论两者中哪一个更具pythonic不感兴趣。相反,我想知道一种方法在资源,性能等方面是否具有实际优势。我已阅读this bit of documentation,但我无法确定使用obj = Foo.objects.first() assert obj.value is True # value of foo obj is updated somewhere to False and I want to test below assert Foo.objects.get(id=obj.id).value is False 是否有优势。谢谢!

3 个答案:

答案 0 :(得分:4)

Django来源通常比较容易理解。如果我们查看refresh_from_db() implementation,其核心仍然是使用相同的Foo.objects.get(id=obj.id)方法:

db_instance_qs = self.__class__._default_manager.using(db).filter(pk=self.pk)
...
db_instance_qs = db_instance_qs.only(*fields)
...
db_instance = db_instance_qs.get()

只有几个额外的花里胡哨:

  • deferred字段被忽略
  • 过时的外键引用被清除(根据注释说明)

因此,对于日常使用,可以安全地说它们几乎相同,使用你喜欢的任何东西。

答案 1 :(得分:0)

只是添加到@serg的答案中,在某些情况下,从数据库中显式重新获取会有所帮助,而从数据库中进行刷新并不是那么有用。

在向对象添加权限并在此之后立即检查权限时,就是这种情况,您需要清除该对象的缓存权限,以便您的权限检查能够按预期进行。

根据the permission caching section of the django documentation

第一次需要获取权限检查之后,ModelBackend会在用户对象上缓存权限。这通常适合请求-响应周期,因为通常不会在添加权限后立即检查权限(例如,在管理员中)。如果要添加权限并随后立即检查权限,例如在测试或视图中,最简单的解决方案是从数据库中重新获取用户...

举个例子,考虑一下上面引用的文档中的代码块:

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

from smoothies.models import Smoothie


def force_deblend(user, smoothie):

    # Any permission check will cache the current set of permissions
    if not user.has_perm('smoothies.deblend_smoothie'):

        permission = Permission.objects.get(
            codename='deblend_smoothie',
            content_type=ContentType.objects.get_for_model(Smoothie)
        )
        user.user_permissions.add(permission)

        # Subsequent permission checks hit the cached permission set
        print(user.has_perm('smoothies.deblend_smoothie'))   # False

        # Re-fetch user (explicitly) from db to clear permissions cache
        # Be aware that user.refresh_from_db() won't help here
        user = get_user_model().objects.get(pk=user.pk)

        # Permission cache is now repopulated from the database
        print(user.has_perm('smoothies.deblend_smoothie'))   # True

        ...

    ...

答案 2 :(得分:0)

如果使用缓存的属性,似乎有所不同。

查看此处:

p.roles[0]
<Role: 16888649>
p.refresh_from_db()
p.roles[0]
<Role: 16888649>
p = Person.objects.get(id=p.id)
p.roles[0]
<Role: 16888650>

models.py中的定义:

@cached_property
def roles(self):
    return Role.objects.filter(employer__person=self).order_by("id")