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

Tortoise ORM filter with logical operators

我有两张桌子

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 在它们的 tags 中应该同时包含 foobar

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()

因为您现在不能 group_by 在 Tortoise ORM 中的注释字段上。
这是使用从

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

想法是获取计数等于标签数的记录,在本例中为2 (bar, foo)