首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Django ORM在一个查询中将多个关系连接到多个关系

Django ORM在一个查询中将多个关系连接到多个关系
EN

Stack Overflow用户
提问于 2018-11-20 08:15:30
回答 1查看 5.3K关注 0票数 4

如果我们有两个模型A,B有一个多到多的关系。

我希望获得类似于以下内容的sql查询:

代码语言:javascript
复制
SELECT *
FROM a LEFT JOIN ab_relation 
ON ab_relation.a_id = a.id
JOIN b ON ab_relation.b_id = b.id;

所以在django当我尝试:

代码语言:javascript
复制
A.objects.prefetch_related('bees')

我收到了两个类似于以下内容的查询:

代码语言:javascript
复制
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)有关系的。
  • 中等大小意味着每行4k,太慢意味着大约3秒(在第一次加载时,在redis缓存之前)。请记住,页面上还有其他查询。
  • 实际上,我们只需要B.one_field,但是在尝试了Prefetch('bees', queryset=B.objects.values('one_field'))之后,一个错误告诉您不能在预取中使用values
  • 查询集将用作多选择表单字段的选项,在该字段中,我们需要表示与B有关系的A对象,该对象具有来自B.field的额外字符串。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-20 08:31:05

直接回答跳到第6点)

让我们一步一步地谈。

1) N:M选择。你说你想要这样的查询:

代码语言:javascript
复制
SELECT *
FROM a JOIN ab_relation ON ab_relation.a_id = a.id
JOIN b ON ab_relation.b_id = b.id;

但这不是真正的N:M查询,因为您只获得与are相关的对象,查询应该使用outer joins。至少像:

代码语言:javascript
复制
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;

在其他情况下,您只获得带有相关BB模型。

2) 阅读大表----你说的是“中等大的表”。那么,您确定要从数据库读取整个表吗?这在web环境中并不常见,可以读取大量数据,在这种情况下,您可以对数据进行分页。可能不是一个网络应用?你为什么要看这张大桌子?我们需要背景来回答你的问题。您确定需要两个表中的所有字段吗?

3) Select 您确定需要两个表中的所有字段吗?如果只读取某些值,则此查询将运行得更快。

代码语言:javascript
复制
A.objects.values( "some_a_field", "anoter_a_field", "Bs__some_b_field" )

4) 作为总结。ORM是一个强大的工具,两个单一的读取操作都是“快速”的。我写了一些想法,但也许我们需要更多的上下文来回答你的问题。什么意味着中等大的表,小麦的意思是慢,您对这些数据做什么,每个表的每一行有多少字段或字节,.。

编辑了,因为OP编辑了这个问题。

5) 使用右UI控件。你说:

查询集将用作多选择表单字段的选项,在该字段中,我们需要表示与B有关系的A对象,该对象具有来自B.field的额外字符串。

它看起来像一个反模式发送到客户端4k行为一个表单。我建议您移到一个只加载所需数据的实时控件中。例如,通过某些文本进行过滤。看一看django-select2 2出色的项目。

6)你说

问题是:是否可以通过ORM获得左联接手动写入查询?

答案是:,您可以使用values,正如我在第3点上说的那样。示例:MaterialResultatAprenentatge是N:M关系:

代码语言:javascript
复制
>>> print( Material
          .objects
          .values( "titol", "resultats_aprenentatge__codi" )
          .query )

查询:

代码语言:javascript
复制
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 
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53388750

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档