我有以下模型结构:
class Container(models.Model):
pass
class Generic(models.Model):
name = models.CharacterField(unique=True)
cont = models.ManyToManyField(Container, null=True)
# It is possible to have a Generic object not associated with any container,
# thats why null=True
class Specific1(Generic):
...
class Specific2(Generic):
...
...
class SpecificN(Generic):
...
说,我需要检索与特定Container有关系的所有Specific
类型模型。
对此的SQL或多或少是微不足道的,但这不是问题。不幸的是,我在使用ORM(特别是Django的ORM)方面不是很有经验,所以我可能会错过这里的模式。
以蛮力方式完成时, -
c = Container.objects.get(name='somename') # this gets me the container
items = c.generic_set.all()
# this gets me all Generic objects, that are related to the container
# Now what? I need to get to the actual Specific objects, so I need to somehow
# get the type of the underlying Specific object and get it
for item in items:
spec = getattr(item, item.get_my_specific_type())
这导致大量的db命中(每个通用记录一个,与Container有关),所以这显然不是这样做的方法。现在,也许可以通过直接获取SpecificX对象来完成:
s = Specific1.objects.filter(cont__name='somename')
# This gets me all Specific1 objects for the specified container
...
# do it for every Specific type
这样每个特定类型的数据库都会被命中一次(我猜是可接受的)。
我知道,.select_related()不能与m2m关系一起使用,因此在这里没什么用。
重申一下,最终结果必须是SpecificX对象的集合(不是Generic)。
答案 0 :(得分:2)
我认为你已经概述了两种简单的可能性。要么对Generic执行单个过滤器查询,然后将每个项目转换为其特定子类型(导致n + 1个查询,其中n是返回的项目数),或者对每个特定表格进行单独查询(结果为k)查询,其中k是特定类型的数量。)
实际上值得进行基准测试,看看其中哪些更快。第二个似乎更好,因为它(可能)更少的查询,但这些查询中的每一个都必须与m2m中间表执行连接。在前一种情况下,您只执行一个连接查询,然后执行许多简单查询。一些数据库后端在执行大量小查询时表现得比更少,更复杂的查询更好。
如果第二个实际上对你的用例来说明显更快,并且你愿意做一些额外的工作来清理你的代码,那么应该可以为Generic模型编写一个“预取”的自定义管理器方法“来自给定查询集的相关特定表的所有子类型数据,每个子类型表只使用一个查询;类似于this snippet如何使用批量预取优化通用外键。这将为您提供与第二个选项相同的查询,使用第一个选项的DRYer语法。
答案 1 :(得分:1)
不是一个完整的答案,但你可以通过这样做来避免大量的点击
items= list(items)
for item in items:
spec = getattr(item, item.get_my_specific_type())
而不是:
for item in items:
spec = getattr(item, item.get_my_specific_type())
实际上,通过强制转换为python列表,可以强制django orm加载查询集中的所有元素。然后它在一个查询中执行此操作。
答案 2 :(得分:0)
我不小心碰到了以下帖子,这几乎回答了你的问题:
http://lazypython.blogspot.com/2008/11/timeline-view-in-django.html