提问人:cy23 提问时间:10/23/2023 最后编辑:cy23 更新时间:10/25/2023 访问量:66
如何按相关模型的字段对 Django 查询进行排序?
How can I order a Django query by a field of a related model?
问:
我有这两个模型,和 ,它们是相关的。我的目标是对查询进行排序,使具有最新消息的聊天室(由 确定)显示在结果的顶部。ChatRoom
ChatMessage
ChatRoom
sent_timestamp
虽然我在这个平台上发现了一些类似的问题,但似乎没有一个能准确地解决我的具体问题。
我知道 annotate 方法,我可以用它来在模型的类之外实现这一点,但我有兴趣直接在模型的类中设置顺序。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",)
答:
2赞
willeM_ Van Onsem
10/23/2023
#1
将引入重复:对于每个相关的 ,将列出。ordering = ("-messages__sent_timestamp",)
ChatMessage
ChatRoom
您可以使用最新的时间戳对此进行注释,然后按此排序,因此:
from django.db.models import Max
ChatRoom.objects.alias(latest=Max('messages__sent_timestamp')).order_by('-latest')
1赞
0urz4g
10/23/2023
#2
试试这个:
ChatRoom.objects.all().alias(my_order=Max('chatmessage_set__sent_timestamp')).order_by('-my_order')
0赞
Hassaan AlAnsary
10/25/2023
#3
根据您不使用并希望将其添加到 .
我想您需要默认将此排序应用于所有查询。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
请注意,这会将 A 添加到此模型的所有查询中,这将导致基于数据大小的查询速度变慢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
希望你觉得这有用
评论