【发布时间】:2018-12-12 23:31:09
【问题描述】:
我有这三个模型:
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 和我用来查询的managed = False,例如:Track.objects.filter(trackhastagfoo__isnull=True)。我不认为这是一个优雅且可持续的解决方案,因为它涉及将 Raw SQL 添加到我的迁移中以维护所述视图。
这只是我们需要使用额外条件执行这种左连接的情况的一个示例,但事实是我们在应用程序的更多部分都面临这个问题。
非常感谢!
【问题讨论】:
-
Track.objects.exclude(trackhastag__name='new_release').only('id')对问题中的模型的查询是错误的。 -
@BearBrown 你是对的。现在已更正。对不起!
标签: django django-models