django - 如何在 Django 中使用额外条件离开外部连接
问题描述
我有这三个模型:
class Track(models.Model):
title = models.TextField()
artist = models.TextField()
class Tag(models.Model):
name = models.CharField(max_length=50)
class TrackHasTag(models.Model):
track = models.ForeignKey('Track', on_delete=models.CASCADE)
tag = models.ForeignKey('Tag', on_delete=models.PROTECT)
我想检索所有未使用特定标签标记的曲目。这让我得到了我想要Track.objects.exclude(trackhastag__tag_id='1').only('id')
的:但是当表格增长时它非常慢。这是我在打印查询集时得到.query
的:
SELECT "track"."id"
FROM "track"
WHERE NOT ( "track"."id" IN (SELECT U1."track_id" AS Col1
FROM "trackhastag" U1
WHERE U1."tag_id" = 1) )
我希望 Django 改为发送此查询:
SELECT "track"."id"
FROM "track"
LEFT OUTER JOIN "trackhastag"
ON "track"."id" = "trackhastag"."track_id"
AND "trackhastag"."tag_id" = 1
WHERE "trackhastag"."id" IS NULL;
但是还没有找到这样做的方法。使用原始查询并不是一个真正的选择,因为我必须经常过滤结果查询集。
我发现的最干净的解决方法是在数据库中创建一个视图和一个用于查询的模型TrackHasTagFoo
,例如: . 我不认为这是一个优雅且可持续的解决方案,因为它涉及将 Raw SQL 添加到我的迁移中以维护所述视图。managed = False
Track.objects.filter(trackhastagfoo__isnull=True)
这只是我们需要使用额外条件执行这种左连接的情况的一个示例,但事实是我们在应用程序的更多部分中都面临着这个问题。
非常感谢!
解决方案
如Django #29555中所述,您可以从 Django 2.0 开始FilteredRelation
用于此目的。
Track.objects.annotate(
has_tag=FilteredRelation(
'trackhastag', condition=Q(trackhastag__tag=1)
),
).filter(
has_tag__isnull=True,
)
推荐阅读
- npm - NPM:使用 npm-automation-token 获取 403 whoami
- list - 在 Haskell 中合并 3 个列表
- http - Tomcat 9 总是给出地址已经用于 http/https 连接器
- spring-cloud - 如何在kafka消费者中使用spring cloud sleuth traceId
- sharepoint - 如何获取不同共享点站点的 ACL
- java - WeakReference 的罕见用法?
- java - 如何在 JavaFX 中正确显示第二个 fxml 文件视图?
- mysql - How to find all items in a column that fit a criteria within another column in SQL
- php - Class 'Srmklive\PayPal\Services\ExpressCheckout' not found
- node.js - socket.io:在 Firefox 上阻止跨域请求