【问题标题】:Queryset for ManyToMany relation ordered by number of match from a list多对多关系的查询集按列表中的匹配数排序
【发布时间】:2020-09-01 00:16:03
【问题描述】:

我有两个模型,具有多对多关系的实体和标签:

class Tag(models.Model):
    name = models.CharField(max_length=128)

class Entity(models.Model):
    name              = models.CharField(max_length=128)
    tags              = models.ManyToManyField(Tag)

在一个视图中,我有一个标签 ID 列表,并希望获得前 10 个实体,其中至少有一个标签按它们与我的列表共有的标签数量排序。

我目前正在通过“tags__in”做“至少一个”部分,并在我的查询集末尾添加一个“.distinct()”。这是正确的方法吗?

我可以看到注释中有一个“计数”可以有一些参数,有没有办法只指定我的列表中的 id ? 如果不需要,我是否需要通过这样的 SQL 查询(来自文档)?我担心我会失去相当多的表现。

Blog.objects.extra(
    select={
        'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
    },
)

【问题讨论】:

    标签: django many-to-many django-queryset


    【解决方案1】:

    如果我正确理解了你的问题,我认为这个查询应该做你想做的(我使用的是 django 3.0):

    from django.db.models import Count, Q
    
    Entity.objects.annotate(tag_count=Count("tags", filter=Q(tags__id__in=tag_ids))).filter(
        tag_count__gt=0
    ).order_by("-tag_count")[:10]
    

    生成的 SQL(我正在使用 postgres):

    SELECT "people_entity"."id",
           "people_entity"."name",
           COUNT("people_entity_tags"."tag_id") FILTER (WHERE "people_entity_tags"."tag_id" IN (1, 4, 5, 8)) AS "tag_count"
      FROM "people_entity"
      LEFT OUTER JOIN "people_entity_tags"
        ON ("people_entity"."id" = "people_entity_tags"."entity_id")
     GROUP BY "people_entity"."id"
    HAVING COUNT("people_entity_tags"."tag_id") FILTER (WHERE ("people_entity_tags"."tag_id" IN (1, 4, 5, 8))) > 0
     ORDER BY "tag_count" DESC
     LIMIT 10
    

    小编辑:在导入中添加 Q

    【讨论】:

    • 正是我想要的!非常感谢先生!
    猜你喜欢
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    相关资源
    最近更新 更多