将原始自联接 sql 转换为 Django orm 代码(无内部外键)
Convert a raw self join sql to Django orm code (no internal foreign key)
我有 Article
和 Tag
模型,通过 ArticleTag
的另一个模型具有多对多关系。我想知道对于给定的标签“健康”,它与文章中的其他标签同时出现了多少次。 (例如,在 4 篇带有“Covid”标签的文章中,在 0 篇带有“Infection”标签的文章中,等等)
我可以使用一些 Where 条件和 Group By 子句在 ArticleTag
上执行自联接并获得所需的结果:
SELECT tag.title, COUNT(*) as co_occurrences
FROM app_articletag as t0
INNER JOIN app_articletag t1 on (t0.article_id = t1.article_id)
INNER JOIN app_tag tag on (tag.id = t1.tag_id)
WHERE t0.tag_id = 43 and t1.tag_id != 43
GROUP BY t1.tag_id, tag.title
但是我想尽可能远离原始查询并使用 Django QuerySet API。
我看过其他关于自连接的帖子,但他们的模型都有一个外键。
这是我的 Django 模型:
class Tag(Model):
...
class Article(Model):
tags = models.ManyToManyField(Tag, through='ArticleTag', through_fields=('article', 'tag'))
class ArticleTag(Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE))
article = models.ForeignKey(Article, on_delete=models.CASCADE))
一种方法是这样的,给定 t
是 Health
标签:
ArticleTag.objects.values(
"tag__name"
).annotate(
articles_with_health=Count(
"pk", filter=Q(article__articletag__tag=t)
)
).exclude(tag=t)
这应该 return 结果如下:
[
{'tag__name': 'Infection', 'articles_with_health': 0},
{'tag__name': 'Covid', 'articles_with_health': 4}
]
我有 Article
和 Tag
模型,通过 ArticleTag
的另一个模型具有多对多关系。我想知道对于给定的标签“健康”,它与文章中的其他标签同时出现了多少次。 (例如,在 4 篇带有“Covid”标签的文章中,在 0 篇带有“Infection”标签的文章中,等等)
我可以使用一些 Where 条件和 Group By 子句在 ArticleTag
上执行自联接并获得所需的结果:
SELECT tag.title, COUNT(*) as co_occurrences
FROM app_articletag as t0
INNER JOIN app_articletag t1 on (t0.article_id = t1.article_id)
INNER JOIN app_tag tag on (tag.id = t1.tag_id)
WHERE t0.tag_id = 43 and t1.tag_id != 43
GROUP BY t1.tag_id, tag.title
但是我想尽可能远离原始查询并使用 Django QuerySet API。
我看过其他关于自连接的帖子,但他们的模型都有一个外键。
这是我的 Django 模型:
class Tag(Model):
...
class Article(Model):
tags = models.ManyToManyField(Tag, through='ArticleTag', through_fields=('article', 'tag'))
class ArticleTag(Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE))
article = models.ForeignKey(Article, on_delete=models.CASCADE))
一种方法是这样的,给定 t
是 Health
标签:
ArticleTag.objects.values(
"tag__name"
).annotate(
articles_with_health=Count(
"pk", filter=Q(article__articletag__tag=t)
)
).exclude(tag=t)
这应该 return 结果如下:
[
{'tag__name': 'Infection', 'articles_with_health': 0},
{'tag__name': 'Covid', 'articles_with_health': 4}
]