Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django ORM在一个查询中连接多对多关系_Django_Postgresql_Django Models_Django Orm - Fatal编程技术网

Django ORM在一个查询中连接多对多关系

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_

如果我们有两个具有多对多关系的模型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_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有关系的对象


直接回答跳到第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相关对象。至少像:

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爸爸的狼蛛吗?太好了!很抱歉回复晚了。。。忙于其他事情:)