带有逻辑运算符的 Tortoise ORM 过滤器

问题描述

我有两张桌子

class User(models.Model):
    id = fields.BigIntField(pk=True)
    name = CharField(max_length=100)
    tags: fields.ManyToManyRelation["Tag"] = fields.ManyToManyField(
        "models.Tag",related_name="users",through="user_tags"
    )

class Tag(models.Model):
    id = fields.BigIntField(pk=True)
    name = fields.CharField(max_length=100)
    value = fields.CharField(max_length=100)
    users: fields.ManyToManyRelation[User]

让我们假设这个虚拟数据

#users
bob = await User.create(name="bob")
alice = await User.create(name="alice")

#tags
foo = await Tag.create(name="t1",value="foo")
bar = await Tag.create(name="t2",value="bar")

#m2m
await bob.tags.add(foo)
await alice.tags.add(foo,bar)

现在我想统计同时具有 foobar 标签用户,在本例中为 alice,所以它应该是 1

下面的查询会给我一个单一的过滤级别,但是我如何指定 user 应该在它们的 foo 中同时包含 bartags

u = await User.filter(tags__name="t1",tags__value="foo").count()

解决方法

Tortoise-ORM 为复杂查询提供 Q objects,使用逻辑运算符如 |(or) 和 &(and)。您的查询可以是这样的:


u = await User.filter(Q(tags__name="t1") & (Q(tags__value="foo") | Q(tags__value="bar"))).count()
,

由于目前您无法在 Tortoise ORM 中的注释字段上 group_by
这是使用 here

引用的 having 子句的解决方案
u = await User.filter(Q(tags__value="foo") | Q(tags__value="bar"))
              .annotate(count=Count("id"))
              .filter(count==2)

这个想法是获取计数等于标签数量的记录,在这种情况下为 2 (bar,foo)