Получение отношений из поля ManyToMany с помощью аннотации

У меня есть моя база данных здесь. Где у меня есть 2 пользователя, подключенных к одному экземпляру ChatRoomParticipants с ManyToManyField.

Я пытаюсь получить список связанных пользователей из поля отношения ManyToMany из ChatRoomParticipants, где я не хочу показывать текущего аутентифицированного пользователя в списке с другими полями, т.е. room, присутствующими в модели.

Учитывая, что пользователь f4253fbd90d1471fb54180813b51d610 в настоящее время вошел в систему и связан со всеми ChatRooms через модель ChatRoomParticipants.

То, что я пробовал, но не смог добиться желаемого результата

chatrooms = list(ChatRoomParticipants.objects.filter(user=user).values_list('user__chatroom_users__user__username', 'room').distinct())

#####
chatrooms =  ChatRoomParticipants.objects.filter(user=user).annotate(user!=User(user))

####
chatrooms = Chatrooms.objects.filter(user=user)
rooms = chatrooms.values('user__chatroom_users__user__username').distinct().exclude(user__chatroom_users__user__username=user)

Я хочу получить результат типа

[
    {
        'user': '872952bb6c344e50b6fd7053dfa583de'
        'room': 1
    },
    {
        'user': '99ea24b12b8c400689702b4f25ea0f40'
        'room': 2
    },
    {
        'user': 'eecd66e748744b96bde07dd37d0b83b3'
        'room': 3
    },
]

models.py

class ChatRoom(models.Model):
    name = models.CharField(max_length=256)
    last_message = models.CharField(max_length=1024, null=True)
    last_sent_user = models.ForeignKey(
        User, on_delete=models.PROTECT, null=True)

    def __str__(self):
        return self.name


class Messages(models.Model):
    room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)
    user = models.ForeignKey(User, on_delete=models.PROTECT)
    content = models.CharField(max_length=1024)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.content


class ChatRoomParticipants(models.Model):
    user = models.ManyToManyField(User, related_name='chatroom_users')
    room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)

Мне кажется, что дизайн базы данных неправильный. В частности, поле user в модели ChatRoomParticipants определено как ManyToManyField, но я думаю, что оно должно быть просто ForeignKey, потому что должны быть M2M отношения между User и ChatRoom, а не между User и ChatRoomParticipants.

class ChatRoomParticipants(models.Model):
    user = models.ForeignKey(User, related_name='chatroom_users', on_delete=models.PROTECT)
    room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)

Тогда функция фильтра должна работать.

Сначала необходимо получить список комнат, в которых находится текущий аутентифицированный пользователь:

room_ids = list(ChatRoomParticipants.objects.filter(user=user).values_list('room__id', flat=True))

И вы получаете соседей по комнате:

participants = ChatRoomParticipants.objects.exclude(user__id = user.id).filter(room__id__in = room_ids)

если вы все еще хотите сохранить дизайн вашей БД, то посмотрите ссылку ниже для справки по запросам

[https://docs.djangoproject.com/en/4.0/topics/db/queries/#lookups-that-span-relationships]

Вы можете выполнить запрос из модели User.

from django.db.models import F

User.objects.exclude(
    username=user
).annotate(
    room=F(
        'chatroomparticipants__room'
    )
).filter(room__isnull=False)

Также != в вашей аннотации вы должны рассмотреть класс Q example,

С помощью этого вы можете сделать это отрицание.

from django.db.models import Q

User.objects.filter(
    ~Q(username=user)
)
Вернуться на верх