【问题标题】:prefetch_related and Prefetch object issue, filtering thru reverse Foreign Keyprefetch_related 和 Prefetch 对象问题,通过反向外键过滤
【发布时间】:2018-05-24 01:30:23
【问题描述】:

我有 2 个模型,公司和产品。

class Product(Meta):
    company = models.ForeignKey(Company, related_name='products', on_delete=models.CASCADE)

形成我正在尝试获取公司数据和相应产品的数据库。

我只想从产品中获取名称并按updated_at、created_at 降序排列。

我正在使用 Prefetch 对象和 prefetch_related 并且我对它们的工作方式有很多误解。

def get_queryset(self):
    qs = Company.objects.prefetch_related(
        Prefetch('products', queryset=Product.objects.only('name').order_by('-updated_at', '-created_at'))).get()
    return qs

我收到的错误是:

get() returned more than one Company 

因为我用))) 关闭了prefetch_related 方法/函数:

  1. 我认为get() 将作用于 Company 对象并使用来自 url 的 pk/slug 获取它(在 DetailView 中默认执行)。好像不是这样的。

  2. 我已经在 Prefetch 对象中使用了 'products' 的相关名称,为什么在查询集中需要再次告诉模型 queryset=Product.objects....

我在 django 文档中查看以下示例:

   Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()

如果Prefetch 对象中有“choice_set”,为什么最后会调用choice_set.all()

Django 不是在 prefetch_related 中的 quesryset 中附加了产品到查询集(question.choice_set)吗?

我认为我的问题是我不了解执行顺序,我很困惑方法是如何链接的,即使被')'关闭

【问题讨论】:

标签: django django-queryset


【解决方案1】:

queryset.get() 仅在查询集具有单个对象时才有效。如果它包含零个或多个对象,则会出现错误。

您应该从get_queryset 对象返回一个查询集。在基于类的视图中,过滤 pk/slug 的代码位于 get_object

如果您想获取多个国家/地区的产品,prefetch_related 方法非常有用。我认为Django docs 使用get() 的方式令人困惑——如果查询集只有一个项目,那么prefetch_related 过于复杂。

如果您只有一家公司,则没有优势,如果您单独获取国家/地区,则代码会更简单,例如在get_context_data

def get_context_data(self, **kwargs):
    context = super(MyView, self).get_context_data(**kwargs)
    context['products'] = Product.objects.filter(company=self.object).Product.objects.only('name').order_by('-updated_at', '-created_at')))
    return context

我已经删除了only('name') 电话。这是您可能不需要的优化。

如果你真的想使用prefetch_related,那么删除get()

qs = Company.objects.prefetch_related(
    Prefetch('products', queryset=Product.objects.order_by('-updated_at', '-created_at')))

通过指定上面的查询集,您可以更改顺序(如果您愿意,可以对其进行过滤)。如果您不想自定义查询集,您可以简单地这样做:

Company.objects.prefetch_related('products')

当您使用Question.objects.prefetch_related(...) 时,查询集仍然是问题列表。您需要在各个实例上调用 choice_set.all() 以访问他们的选择。这不会引起任何额外的查询,因为 Django 已经预取了选项。

queryset = Question.objects.prefetch_related(Prefetch('choice_set'))
for question in queryset:
    print(question) # the question
    print(question.choice_set.all())  # the related choices

【讨论】:

  • 谢谢,但我还是想了解 Prefetch 对象是如何工作的,以及如何使用,而不是使用单独的上下文键
猜你喜欢
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-08
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
相关资源
最近更新 更多