Django ORM несколько различных и упорядочены - PullRequest
0 голосов
/ 01 сентября 2018

Я работаю над простым приложением чата. Мне нужно запросить базу данных для пользователя, чтобы получить последнее сообщение о разговоре пользователя с другими пользователями. То же, что и на главной странице WhatsApp и Telegram.

Модель:

class CHAT(models.Model):
    sender_uid = models.CharField(max_length=150, db_index=True)
    receiver_uid = models.CharField(max_length=150, db_index=True)
    message = models.TextField(verbose_name='Message Text')
    created = models.IntegerField(default=created_time_epoch)

Я пробовал этот запрос:

message_list = self.model.objects.filter(Q(sender_uid=user_uid)|Q(receiver_uid=user_uid)).order_by('receiver_uid', 'sender_uid', '-created').distinct('receiver_uid', 'sender_uid')

Выход:

<QuerySet [<CHAT: ted@ted.com Message: hello 4 To: saeed@saeed.com>, <CHAT: marshal@marshal.com Message: hello6 To: saeed@saeed.com>, <CHAT: saeed@saeed.com Message: hello 5 To: ted@ted.com>]>

Моя проблема в том, что я получаю два последних сообщения из каждого разговора (если оба пользователя отправляют сообщения друг другу), в одном из них пользователь является отправителем, а в другом - пользователь является получателем.

А пока я справлюсь с кодом ниже:

message_send_list = list(self.model.objects.filter(sender_uid=user_uid).order_by('receiver_uid', '-created').distinct('receiver_uid'))
message_receive_list = list(self.model.objects.filter(receiver_uid=user_uid).order_by('sender_uid', '-created').distinct('sender_uid'))
temp_list = []
for s_message in message_send_list:
    r_message = next((item for item in message_receive_list if item.sender_uid == s_message.receiver_uid), None)
    if r_message is not None:
        message_receive_list.pop(message_receive_list.index(r_message))
        if s_message.created > r_message.created:
            temp_list.append(s_message)
        else:
             temp_list.append(r_message)
    else:
        temp_list.append(s_message)
temp_list.extend(message_receive_list)

Выход:

[<CHAT: saeed@saeed.com Message: hello 5 To: ted@ted.com>, <CHAT: marshal@marshal.com Message: hello6 To: saeed@saeed.com>]

Мой вопрос: как я могу получить этот результат в одном запросе? Проблема в том, что пользователь может быть отправителем и получателем сообщения, и я не могу определить, какое из них является последним сообщением разговора. Как отфильтровать или отличить по этому?

1 Ответ

0 голосов
/ 02 сентября 2018

Основываясь на описании проблемы, вы делаете ее слишком сложной. Вы можете получить другого человека с условным выражением [Django-doc] . Итак, сначала сделав «сокращение», когда мы берем другого человека, мы можем использовать для этого фильтр уникальности:

from django.db.models import Case, F, When

last_messages = self.model.objects.filter(
    Q(sender_uid=user_uid) | Q(receiver_uid=user_uid)
).annotate(
    <b>other=</b>Case(
        When(sender_uid=user_uid, then=F('receiver_uid')),
        default=F('sender_uid'),
        output_field=CharField()
    )
).order_by(<b>'other', '-created'</b>).distinct(<b>'other'</b>)

Далее все объекты Chat будут иметь дополнительный атрибут: other, который, таким образом, содержит сторону, отличную от user_uid.

...