Получение отношений из поля 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)
)