如果我们有2个具有多对多关系的模型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')
我得到2条类似的查询:
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获得左联接手动编写的查询?
进行编辑以回答一些澄清:
是的,最好使用LEFT OUTER JOIN
来获得查询集中的所有A,而不仅仅是与B有关系的SQL(更新的sql)。
适度的大意味着每个行大约4k行,太慢的意味着大约3秒(在第一次加载时,在redis缓存之前。)请记住,页面上还有其他查询。
实际上是的,我们只需要B.one_field,但是尝试使用Prefetch('bees', queryset=B.objects.values('one_field'))
时出现错误,提示您无法在预取中使用values
。
查询集将用作多选表单域的选项,在这里我们需要用B.field中的额外字符串表示与B有关系的A对象。
答案 0 :(得分:2)
有关直接答案,请跳至第6点)
让我们一步一步地讲。
1) N:M选择。您说您想要这样的查询:
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相关的对象。该查询应使用outer joins
。至少喜欢:
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;
在其他情况下,您只会获得具有相关A
的{{1}}个模型。
2)阅读大表,您说的是“中度大表” 。然后,确定要从数据库读取整个表吗?在Web环境中,读取大量数据并不常见,在这种情况下,您可以分页数据。可能不是网络应用?为什么需要阅读这张大桌子?我们需要上下文来回答您的问题。您确定需要两个表中的所有字段吗?
3)选择* from 您确定您需要两个表中的所有字段吗?可能是,如果您仅读取某些值,则此查询将运行得更快。
B
4)摘要。 ORM是一个功能强大的工具,两次读取操作都是“快速”的。我写了一些想法,但也许我们需要更多的上下文来回答您的问题。什么意味着中等大小的表,小麦意味着缓慢,您在处理这些数据,每个表的每一行有多少个字段或字节,...。
已编辑,因为OP已编辑了问题。
5)使用正确的UI控件。你说:
queryset将用作多选表单域的选项,在这里我们需要用B.field中的额外字符串表示与B有关系的A对象。
向表单发送4k行到客户端看起来像是反模式。我建议您转到仅加载所需数据的实时控件。例如,按某些文本进行过滤。看看django-select2很棒的项目。
6)你说
问题是:是否可以通过ORM获得左联接手动编写的查询?
答案是:是,您可以使用A.objects.values( "some_a_field", "anoter_a_field", "Bs__some_b_field" )
进行操作,正如我在第3点所说。示例:values
和Material
是一个N:M关系:
ResultatAprenentatge
查询:
>>> print( Material
.objects
.values( "titol", "resultats_aprenentatge__codi" )
.query )