【问题标题】:Order by nested objects date按嵌套对象日期排序
【发布时间】:2021-11-09 12:53:13
【问题描述】:

我正在构建一个聊天应用程序,并有以下模型代表聊天室、聊天消息和未读消息计数器

class ChatRoom(BaseModel):
    name = models.CharField(max_length=255, default='', blank=True)
    participants = models.ManyToManyField('accounts.User', related_name='chat_rooms')

class ChatMessage(BaseModel):
    text = models.TextField(default='', blank=True)
    owner = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
    room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='messages')

class ChatRoomUnreadMessagesCounter(BaseModel):
    room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE, related_name='unread_counters')
    owner = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
    messages_count = models.IntegerField(default=0)

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_deleted = models.BooleanField(default=False)

    class Meta:
        abstract = True

我想创建一个 API 视图,该视图将返回按以下方式排序的 ChatRoom 对象列表:ChatRoom 具有按消息计数排序的未读消息的对象 -> ChatRoom 具有消息的对象最新消息 created_at 后进先出 -> ChatRoom 按字母顺序排序的对象。我将如何正确构建我的查询集?

这是预期的结果输出

| Room Name | Unread Messages | Last Message          |
| Rean      | 2               | 09.11.2021T12:00:00   |
| Ash       | 1               | 09.11.2021T12:00:24   |
| Altina    | 0               | 09.11.2021T12:15:00   |
| Juna      | 0               | 09.11.2021T12:14:00   |
| Kurt      | 0               | 09.11.2021T12:13:00   |
| Musse     | 0               | 09.11.2021T12:12:00   |
| Sharon    | 0               | No messages yet       |

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    这不是微不足道的。希望有人得到一个更简单的答案。我的包括SubQuery

        from django.db.models import OuterRef, Subquery
    
        # get query which references an 'id' field of the parent qs
        latest_message_subq = Subquery(Message.objects.filter(
            room=OuterRef("id")).order_by("-created_at").values('created_at')[:1]
        )
    
        # annotate the unread count per room
        # assumes there's only a single counter per owner
        unread_count_subq = Subquery(ChatRoomUnreadMessagesCounter.objects.filter(
            room=OuterRef("id"), owner=user).values('messages_count')[:1]
        )
    
        # Room.objects.all() is the parent qs
        # So the OuterRef("id") is pointing to a room id
        rooms = Room.objects.annotate(
            latest_message_time=latest_message_subq,
            unread_count= unread_count_subq
        )
        # every object in the rooms qs should now have the attributes latest_message_time and unread_count; you can loop it to verify
    
        rooms = rooms.order_by('-unread_count', '-latest_message', 'name')
    

    编辑:更改为在最后获得一个房间 qs

    【讨论】:

    • 您好,感谢您的回答。我需要的是ChatRooms 的列表,而不是计数器。
    • 不用担心。 values_list 准确返回您的预期结果。我会在几秒钟内把答案转过来得到一个房间查询集。
    • 非常感谢,我会尽快试一试
    • 有没有办法让这个工作与实际的查询集而不是 valuest_list 一起工作?我正在使用 django rest 框架,如果我转换查询集,我会失去它的默认分页和过滤后端
    • .first() 是否评估查询集?这可能是这里的问题,因为我们试图在子查询中使用它
    猜你喜欢
    • 1970-01-01
    • 2012-03-06
    • 2016-02-19
    • 2019-06-25
    • 1970-01-01
    • 2019-07-05
    • 2022-08-17
    • 2017-08-01
    • 2018-09-25
    相关资源
    最近更新 更多