【问题标题】:Could not figure out the use of prefetch_related in django无法弄清楚 django 中 prefetch_related 的使用
【发布时间】:2023-04-03 08:49:01
【问题描述】:

有一种情况,我想显示用户的总购买量。我确实在用户配置文件模型中使用了@property。幸运的是,它按我的预期工作。但我想使用 prefetch_related 来优化 django 查询,因为用户的总购买量是从 order_history 计算出来的,它与 OrderMenu 有 ManyToMany 关系。

我做得怎么样?

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    slug = models.SlugField(unique=True,blank=True,null=True)
    restaurant = models.ManyToManyField(Restaurant, blank=True)
    order_history = models.ManyToManyField(OrderMenu, blank=True)
    # favorites = models.ManyToManyField(Restaurant)
    is_owner = models.BooleanField(default=False)

    @property
    def total_purchase(self):
        total_purchase = 0
        # user_order = UserProfile.objects.prefetch_related('order_history').get(slug=self.slug)
        userprofile = UserProfile.objects.get(slug=self.slug)
        user_order = userprofile.order_history.all()
        for usr in user_order:
            total_purchase += usr.get_cost()
        return total_purchase

在这个解决方案中,不是

userprofile = UserProfile.objects.get(slug=self.slug) user_order = userprofile.order_history.all()

等价于

user_order=UserProfile.objects.prefetch_related('order_history').get(slug=self.slug)

我对 prefetch_related 感到非常困惑。谁能用简单的语言启发我?对不起,我不是以英语为母语的人。

【问题讨论】:

    标签: python django django-models query-optimization django-orm


    【解决方案1】:

    两者的区别是

    如果发生

    userprofile = UserProfile.objects.get(slug=self.slug)#hits 数据库

    此查询根据数据库中的条件获取用户配置文件的对象

    user_order = userprofile.order_history.all()#再次点击数据库

    此查询使用 userprofile 对象再次访问数据库获取 user_order 查询集。

    即userprofile 命中数据库以及 user_order

    在这种情况下

    user_order=UserProfile.objects.prefetch_related('order_history').get(slug=self.slug)

    user_order 查询集集不仅返回用户配置文件对象,还返回与 UserProfile 对象相关的“order_history”查询集,一次命中数据库。现在,当您使用 user_order 对象访问“order_history”查询集时,它不会命中数据库,而是从“user_order”的预取 QuerySet 缓存中获取“order_history”的查询集。更多关于它here.

    【讨论】:

    • 这就是我对 prefetch_related 的理解,所以我做了 user_order=UserProfile.objects.prefetch_related('order_history').get(slug=self.slug) 并遍历 user_order 以使用 total + 计算总成本usr.get_cost() 但我得到一个错误,'UserProfile' object is not iterable
    • 我也添加了模型部分。为什么当我迭代使用 prefetch_related 来获取 OrderMenu 的 get_cost 函数的 user_order 时,会出现“UserProfile”对象不可迭代的错误?
    • user_order 是 UserProfile 的单个对象,它不是查询集,您不能使用 user_order 进行迭代。如果你想迭代不要使用get,用户过滤来获取查询集而不是对象。类似于 user_order=UserProfile.objects.prefetch_related('order_history').filter(slug=self.slug) 的东西,它返回查询集(基于匹配的 UserProfile 对象列表)。
    • 那么我无法访问 OrderMenu 的属性和函数,因为它只是 UserProfile 的对象。
    • 我不知道 OrderMenu 是什么,但如果它是“OrderHistory”(与 UserProfile 相关的模型),您可以使用该对象访问属性和函数。当你使用 get 时,唯一的区别是你得到一个不是可迭代的对象而不是列表。您可以使用对象访问,但不能使用 for 循环,这就是我的观点。希望这对你有帮助,如果有,请接受我的回答谢谢。
    猜你喜欢
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多