如何通过相关模型的字段对 Django 查询进行排序?

问题描述 投票:0回答:3

我有这两个模型,

ChatRoom
ChatMessage
,它们是相关的。我的目标是对
ChatRoom
查询进行排序,使包含最新消息的房间(由
sent_timestamp
确定)显示在结果的顶部。

虽然我在这个平台上发现了一些类似的问题,但似乎没有一个能够准确解决我的具体问题。

我知道注释方法,我可以使用该方法在模型的

Meta
类之外实现此目的,但我有兴趣直接在
Meta
模型的
ChatRoom
类中设置排序。

有没有办法在 Meta 类中实现这种排序,或者我应该考虑其他方法吗?

class ChatRoom(models.Model):
    members = models.ManyToManyField(User, related_name="chat_rooms")

    class Meta:
        # Intended for this to order the chat rooms so that the room that
        # has the most recent chat message come first, but it's not working
        ordering = ("-messages__sent_timestamp",)


class ChatMessage(models.Model):
    room = models.ForeignKey(ChatRoom, models.CASCADE, related_name="messages")
    sender = models.ForeignKey(User, models.CASCADE)
    text = models.TextField(validators=[MaxLengthValidator(280)])
    sent_timestamp = models.DateTimeField(auto_now_add=True)
    delivery_timestamp = models.DateTimeField(null=True, blank=True)
    read_timestamp = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ("-sent_timestamp",)
python django django-models django-queryset
3个回答
2
投票

ordering = ("-messages__sent_timestamp",)
将引入重复:对于每个相关的
ChatMessage
ChatRoom
将被列出。

你可以用最新的时间戳来注释它,然后按它排序,所以:

from django.db.models import Max

ChatRoom.objects.alias(latest=Max('messages__sent_timestamp')).order_by('-latest')

1
投票

试试这个:

ChatRoom.objects.all().alias(my_order=Max('chatmessage_set__sent_timestamp')).order_by('-my_order')

有关 django 中聚合的文档


0
投票

基于您不使用

annotate
并希望将其添加到
Meta
的请求。 我想您需要在所有查询中默认应用此顺序。

我认为你不能在

Meta
中做到这一点 但是,您可以在
Manager
中做到这一点。您可以将其分配给
objects

将其用作默认管理器
# managers.py
class ChatRoomManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset.alias(latest=Max('messages__sent_timestamp')).order_by('-latest')
        # based on "Willem Van Onsem"'s answer
        return queryset

# models.py
class ChatRoom(models.Model):
    ...

    objects = ChatRoomManager() # default manager

考虑到这会为您对此模型的所有查询添加

join
,这将导致基于您的数据大小的查询速度变慢

如果您想有办法禁用随意订购,您可以执行以下操作

# managers.py
class ChatRoomManager(models.Manager):
    def __init__(self, no_ordering: bool = False):
        super().__init__()
        self.no_ordering= no_ordering

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.no_ordering:
            return queryset

        queryset = queryset.alias(latest=Max('messages__sent_timestamp')).order_by('-latest')
        return queryset

# models.py
class ChatRoom(models.Model):
    ...

    objects = ChatRoomManager() # default manager
    raw_objects = ChatRoomManager(no_ordering=True) # original manager

希望您觉得这很有用

© www.soinside.com 2019 - 2024. All rights reserved.