Django ORM在一个查询中连接多对多关系
如果我们有两个具有多对多关系的模型A,B 我希望获得类似以下内容的sql查询:Django ORM在一个查询中连接多对多关系,django,postgresql,django-models,django-orm,Django,Postgresql,Django Models,Django Orm,如果我们有两个具有多对多关系的模型A,B 我希望获得类似以下内容的sql查询: SELECT * FROM a LEFT JOIN ab_relation ON ab_relation.a_id = a.id JOIN b ON ab_relation.b_id = b.id; 因此,在django,当我尝试: A.objects.prefetch_related('bees') 我收到两个类似于以下内容的查询: SELECT * FROM a; SELECT ab_relation.a_
SELECT *
FROM a LEFT JOIN ab_relation
ON ab_relation.a_id = a.id
JOIN b ON ab_relation.b_id = b.id;
因此,在django,当我尝试:
A.objects.prefetch_related('bees')
我收到两个类似于以下内容的查询:
SELECT * FROM a;
SELECT ab_relation.a_id AS prefetch_related_val_a_id, b.*
FROM b JOIN ab_relation ON b.id = ab_relation.b_id
WHERE ab_relation.a_id IN (123, 456... list of all a.id);
考虑到A和B有相当大的表,我发现django的方式对于我的需要来说太慢了
问题是:是否可以通过ORM获得手动编写的左连接查询
编辑以回答一些澄清:
- 是的,a
更适合于获取查询集中的所有a,而不仅仅是那些与B(更新的sql)有关系的a左外部联接
- 中等大小意味着每行约4k行,太慢意味着约3秒(第一次加载时,在redis缓存之前)。请记住页面上还有其他查询
- 实际上是的,我们只需要B.one_字段,但是已经尝试了
一个错误说您不能在预取中使用预取('bees',queryset=B.objects.values('one_字段'))
值
- queryset将用作multi-select表单字段的选项,在该字段中,我们需要用B字段中的额外字符串表示与B有关系的对象
SELECT *
FROM a JOIN ab_relation ON ab_relation.a_id = a.id
JOIN b ON ab_relation.b_id = b.id;
但这不是一个真正的N:M查询,因为您只获得了查询应该使用的外部联接的a-B相关对象。至少像:
SELECT *
FROM a left outer JOIN
ab_relation ON ab_relation.a_id = a.id left outer JOIN
b ON ab_relation.b_id = b.id;
在其他情况下,您只能获得带有相关B
的A
型号
2) 读大桌子你说“中等大小的桌子”。然后,您确定要从数据库读取整个表吗?在web环境中读取大量数据是不常见的,在这种情况下,可以对数据进行分页。可能不是web应用程序?你为什么要看这么大的桌子?我们需要背景来回答你的问题。是否确实需要两个表中的所有字段
3) 选择*from您确定需要两个表中的所有字段吗?如果您只读取一些值,则此查询可能会运行得更快
A.objects.values( "some_a_field", "anoter_a_field", "Bs__some_b_field" )
4) 作为摘要。ORM是一个强大的工具,两个单读操作“快速”。我写了一些想法,但也许我们需要更多的背景来回答你的问题。什么意味着中等大的表,小麦意味着慢,你用这些数据做什么,每个表中每行有多少字段或字节
编辑了EDD,因为OP编辑了问题
5) 使用右UI控件。你说:
queryset将用作multi-select表单字段的选项,在该字段中,我们需要用B字段中的额外字符串表示与B有关系的对象
它看起来像是一种反模式,用于向客户机发送4k行的表单。我建议您移动到只加载所需数据的活动控件。例如,按某些文本进行过滤。来看看这个很棒的项目吧
6) 你说
问题是:是否可以通过ORM获得手动编写的左连接查询
答案是:是,您可以使用值
,正如我在第3点所说的。示例:Material
和resultataprenenttge
是一个N:M关系:
>>> print( Material
.objects
.values( "titol", "resultats_aprenentatge__codi" )
.query )
查询:
SELECT "material_material"."titol",
"ufs_resultataprenentatge"."codi"
FROM "material_material"
LEFT OUTER JOIN "material_material_resultats_aprenentatge"
ON ( "material_material"."id" =
"material_material_resultats_aprenentatge"."material_id" )
LEFT OUTER JOIN "ufs_resultataprenentatge"
ON (
"material_material_resultats_aprenentatge"."resultataprenentatge_id" =
"ufs_resultataprenentatge"."id" )
ORDER BY "material_material"."data_edicio" DESC
谢谢,为您的问题更新了一些澄清。我知道通过xhr过滤可能是一个解决方案,但这仍然不能回答问题。@DavidVeza,我已将样本更改为N:M样本。@DavidVeza,您喜欢Dice爸爸的狼蛛吗?太好了!很抱歉回复晚了。。。忙于其他事情:)