tortoise / tortoise-orm

Familiar asyncio ORM for python, built with relations in mind
https://tortoise.github.io
Apache License 2.0
4.67k stars 390 forks source link

Can't find anyway to filter model with many to many field. #1062

Open Wiper-R opened 2 years ago

Wiper-R commented 2 years ago

I tried so many times but can't get it working.. I was expecting tortoise to be same like django-orm but it is not acting like that.

My Models

class User(models.Model):
    id = SnowflakeField(pk=True)
    username = fields.CharField(max_length=255, unique=True)
    firstname = fields.CharField(max_length=25)
    lastname = fields.CharField(max_length=25)
    email = EmailField(required=True, unique=True)
    password = fields.CharField(max_length=4096)

class Channel(models.Model):
    id = SnowflakeField(pk=True)
    recipients = fields.ManyToManyField("api.User", related_name="recipients")

Now I am having two recipients A and B and I want to filter channel which contains both recipients A and B. I tried using nested filter functions but it doesn't seem to work... While in django-orm it works perfectly.

Is there any way to achieve this? Or I have to write custom queries for that?

dstlny commented 2 years ago

From tortoise.expression import Q

filters = [Q(Q(recipients__id=user_1.id) & Q(recipients__id=user_2.id))]
await Channel.filter(*filters)

Would the above not work?

henadzit commented 2 days ago

It's hard to say what's the exact issue because there is no actual code but I tried the following with the latest version and it seems to work in the same way as Django:

    user1 = await User.create(username="1")
    user2 = await User.create(username="2")

    channel = await Channel.create(name="test")
    await channel.recipients.add(user1, user2)

    channels = await Channel.all().filter(recipients__in=[user1, user2])
    print(channels)

prints [<Channel: 1>, <Channel: 1>]