代码之家  ›  专栏  ›  技术社区  ›  mastisa

Django-ORM多重distinct和order by

  •  1
  • mastisa  · 技术社区  · 6 年前

    我在开发一个简单的聊天软件。我需要查询数据库中的一个用户,以获取用户对话的最后一条消息给其他用户。与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 回复  |  直到 6 年前
        1
  •  1
  •   willeM_ Van Onsem    6 年前

    根据对问题的描述,你把它弄得有点太复杂了。您可以获得 其他人 用一个 conditional expression [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(
        other=Case(
            When(sender_uid=user_uid, then=F('receiver_uid')),
            default=F('sender_uid'),
            output_field=CharField()
        )
    ).order_by('other', '-created').distinct('other')

    Chat 对象将有一个额外属性: other 因此包含了非- user_uid 侧面。