Dav*_*eza 4 django postgresql django-models django-orm
如果我们有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;
Run Code Online (Sandbox Code Playgroud)
所以在Django,当我尝试:
A.objects.prefetch_related('bees')
Run Code Online (Sandbox Code Playgroud)
我收到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);
Run Code Online (Sandbox Code Playgroud)
鉴于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在预取中使用。
queryset将用作多选表单域的选项,在这里我们需要用B.field中的额外字符串表示与B有关系的A对象。
对于直接答案,请跳至第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;
Run Code Online (Sandbox Code Playgroud)
但这不是真正的N:M查询,因为您仅获得与AB相关的对象,该查询应使用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;
Run Code Online (Sandbox Code Playgroud)
在其他情况下,您只会A获得具有相关的模型B。
2)阅读大表您说“中等大表”。然后,确定要从数据库读取整个表吗?在Web环境中,读取大量数据并不常见,在这种情况下,您可以分页数据。可能不是网络应用?为什么需要阅读这张大桌子?我们需要上下文来回答您的问题。您确定需要两个表中的所有字段吗?
3)选择*。确定您需要两个表中的所有字段吗?如果您只读取某些值,则此查询可能会运行得更快。
A.objects.values( "some_a_field", "anoter_a_field", "Bs__some_b_field" )
Run Code Online (Sandbox Code Playgroud)
4)作为总结。ORM是一个功能强大的工具,两次读取操作都是“快速”的。我写了一些想法,但也许我们需要更多的上下文来回答您的问题。什么表示适中的大表,wheat表示慢,这是您在处理这些数据,每个表的每一行有多少个字段或字节,...。
Editedd由于OP编辑了问题。
5)使用正确的UI控件。你说:
queryset将用作多选表单域的选项,在这里我们需要用B.field中的额外字符串表示与B有关系的A对象。
看起来像反模式,将表单的4k行发送到客户端。我建议您转到仅加载所需数据的实时控件。例如,按某些文本进行过滤。看看django-select2很棒的项目。
6)你说
问题是:是否可以通过ORM获得左联接手动编写的查询?
答案是:是的,你可以用它做的values,因为我说的第3点样品:Material和ResultatAprenentatge一个N:M关系:
>>> print( Material
.objects
.values( "titol", "resultats_aprenentatge__codi" )
.query )
Run Code Online (Sandbox Code Playgroud)
查询:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
877 次 |
| 最近记录: |