如何在Django中加入?

时间:2013-12-27 11:07:25

标签: python django django-queryset

我有以下型号:

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棉花。以下是一些表格(省略ProjectUser)。

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

也就是说,我只想在ProjectItemInventory上加入partuser

编辑2:一种可能性是做两个查询(对象,相关对象)并在Python中进行连接,如下所述:

http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

与在数据库中进行连接相比,我不会称之为高效,但它可能比n + 1查询更好。

3 个答案:

答案 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')

希望这会对你有所帮助。 谢谢:))