在distinct()之后的Django order_by。还是截然不同

时间:2014-04-20 15:12:30

标签: python django distinct annotate

我需要像

这样的东西
user_messages = UserMessage.objects.filter(Q(from_user=user) | Q(to_user=user)).order_by('dialog_id').distinct('dialog_id').order_by('created')

当然,它不起作用。我发现我应该使用annotate(),但对我来说似乎很安静,我是Django的新手。你能救我吗?

1 个答案:

答案 0 :(得分:1)

这是我必须实现类似功能的代码。也许它会对你有用。

在视图中:

queryset = Conversation.objects.filter(Q(user_1=user) | Q(user_2=user)).filter(
                Q(messages__sender=user, messages__archived_by_sender=False) |
                Q(messages__recipient=user, messages__archived_by_recipient=False)).annotate(
                last_activity=Max("messages__created")).order_by("-last_activity")

模型看起来像:(方法等省略)

class Conversation(models.Model): # there is only one of these for each pair of users who message one another
    user_1 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="conversations_as_user_1")
    user_2 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="conversations_as_user_2")
    read_by_user_1 = models.BooleanField(default=False)
    read_by_user_2 = models.BooleanField(default=False)

    class Meta:
        unique_together = (("user_1", "user_2"),)

class Message(TimeTrackable):
    conversation = models.ForeignKey(Conversation, related_name="messages", blank=True, help_text="the conversation between these two users (ALWAYS selected automatically -- leave this blank!)")
    sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="messages_sent")
    recipient = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="messages_received")
    text = models.TextField() # flat text, NOT bleached or marksafe
    archived_by_sender = models.BooleanField(default=False)
    archived_by_recipient = models.BooleanField(default=False)

这适用于在同一个用户之间永远不会有多个单独的会话对象的应用程序,但您可以使用存档功能存档所有邮件(从您的角度来看),这与从中删除对话一样好。用户的观点。此外,"阅读"状态存储在会话中,而不是存储在消息上。

为了保证没有两个用户拥有多个"会话"对话中的对象,对话中的user_1始终是较低的用户ID,而user_2始终是较高的用户ID。 (事实上​​,我没有及时想到这个聪明的想法来实际实现它,所以相反,我有复杂和不必要的重写save()逻辑。但如果我再做一次,我会做这部分也可以调用字段user_loweruser_higher或类似的字段来表达清楚。)

让我们打破视图代码:

获取当前用户为user_1或user_2的所有会话对象。通过过滤器,要求返回的任何会话对象至少有一些当前用户可见的消息尚未归档。对话没有时间戳,但是消息有,所以通过最近的活动来注释对话列表。然后通过带注释的时间戳排序。

这可以避免任何distinct()工作,因为您使用连接而不是带有连接的消息列表来提取对话列表。