shy*_*ent 5 django orm many-to-many django-models django-queryset
我有以下模型结构:
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):
...
Run Code Online (Sandbox Code Playgroud)
比如说,我需要检索Specific
与特定Container有关系的所有类型的模型.
用于此的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())
Run Code Online (Sandbox Code Playgroud)
这导致了大量的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
Run Code Online (Sandbox Code Playgroud)
这样每个特定类型的数据库都会被命中一次(我猜是可以接受的).
我知道,.select_related()不适用于m2m关系,因此在这里没有多大帮助.
重申一下,最终结果必须是SpecificX对象的集合(不是Generic).
我认为您已经概述了两种简单的可能性。您可以对 Generic 进行单个过滤查询,然后将每个项目转换为其 Specific 子类型(结果为 n+1 个查询,其中 n 是返回的项目数),或者对每个 Specific 表进行单独的查询(结果为 k查询,其中 k 是特定类型的数量)。
实际上值得进行基准测试,看看其中哪一个实际上更快。第二个似乎更好,因为它(可能)更少的查询,但每个查询都必须与 m2m 中间表执行联接。在前一种情况下,您只执行一个连接查询,然后执行许多简单的查询。一些数据库后端在处理大量小型查询时比处理更少、更复杂的查询时表现更好。
如果第二个对于您的用例来说实际上要快得多,并且您愿意做一些额外的工作来清理代码,那么应该可以为通用模型编写一个自定义管理器方法来“预取”所有来自给定查询集的相关特定表的子类型数据,每个子类型表仅使用一个查询;类似于此代码片段如何通过批量预取来优化通用外键。这将为您提供与第二个选项相同的查询,并使用第一个选项的 DRYer 语法。
归档时间: |
|
查看次数: |
1979 次 |
最近记录: |