我有以下型号:
class Part(models.Model):
user = models.ForeignKey(User)
part_number = models.CharField()
class Inventory(models.Model):
user = models.ForeignKey(User)
part = models.ForeignKey(Part)
stock = models.IntegerField()
storage_location = ...
class Project(models.Model):
user = models.ForeignKey(User)
name = models.CharField()
class ProjectItem(models.Model):
project = models.ForeignKey(Project)
part = models.ForeignKey(Part)
quantity = models.IntegerField()
给定部件可以有多个Inventory
个对象,每个存储位置一个。给定Project
,我想获得所有ProjectItem
的列表以及每个Inventory
部分的相应ProjectItem
个对象。这是否可以使用Django查询?
我能做到
for pi in ProjectItem.objects.filter(project=project):
for inv in Inventory.objects.filter(user=user, part=pi.part)
...
但我不想对每个ProjectItem进行查询。我想这样做:
project_items = ProjectItem.objects.filter(project=project,
part__inventory__user=user)
但我不知道如何获取查询中匹配的Inventory对象。
有什么想法吗?
编辑:让我用一个例子来澄清。整个修复Project
A和User
棉花。以下是一些表格(省略Project
和User
)。
ProjectItem
:
Part Quantity
-----------------------
X 2
Y 1
Inventory
:
Part Stock Location
---------------------
X 91 S
X 13 T
Y 14 S
Y 101 U
我想要的(以表格形式)是:
Part Quantity Stock Location
------------------------------------
X 2 91 S
X 2 13 T
Y 1 14 S
Y 1 101 U
也就是说,我只想在ProjectItem
和Inventory
上加入part
和user
。
编辑2:一种可能性是做两个查询(对象,相关对象)并在Python中进行连接,如下所述:
http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/
与在数据库中进行连接相比,我不会称之为高效,但它可能比n + 1查询更好。
答案 0 :(得分:1)
prefetch_related(*lookups)
返回一个QuerySet,它将在一个批处理中自动检索每个指定查找的相关对象。
https://docs.djangoproject.com/en/1.6/ref/models/querysets/#prefetch-related
答案 1 :(得分:0)
您将需要使用prefetch_related,它是select_related工具的扩展。它们都是usefool工具,可以帮助您在相关模型上进行过滤时防止多次数据库命中。
这是一种性能提升,导致(有时更大) 查询但意味着以后使用外键关系不需要 数据库查询。 (source)
prefetch_related类似于select_related,但使用pythonic(非常可靠地优化)代码来连接不同的查询。在你的情况下,我认为你必须使用prefetch_related,因为你正在经历一个反向关系(从零件到库存)。在代码中,看起来像这样:
project_items = ProjectItem.objects.filter(project=project, part__inventory__user=user).prefetch_related('part__inventory_set')
for pi in project items:
for pi.part.inventory_set.all():
...
看起来你每次都在点击数据库,但是当你使用prefetch_related时,当你调用pi.part.inventory_set.all()
时,django知道不会再次访问数据库,而是从缓存中获取它。
重要提示 - 这不是一个神奇的功能,它只适用于all()
。使用pi.part.inventory_set.filter(...)
会导致其他查询,因此请谨慎使用。
答案 2 :(得分:0)
您可以使用values
来帮助您检索任何相关数据。比如
ProjectItem.objects.all().extra(select={'inventory__stock':'stock','inventory__location':'location'}).values('part', 'quantity', 'stock','location')
希望这会对你有所帮助。 谢谢:))