【问题标题】:Annotate with latest related object in Django在 Django 中使用最新的相关对象进行注释
【发布时间】:2015-08-12 05:49:35
【问题描述】:

我有一个模特Conversation 和一个模特Message

模型Message 有一个会话外键、一个文本字段和一个日期字段。

如何列出所有对话并为每个对话获取最新消息和最新消息的日期?

我猜是这样的

Conversation.objects.annotate(last_message=Max('messages__date'))

但它只会给我最新的日期。我希望last_message 包含最后一条消息的文本和它的创建日期。也许我需要使用 prefetch_related?

【问题讨论】:

    标签: python django django-models django-queryset


    【解决方案1】:

    从 Django 1.11 开始,你可以使用Subqueries expressions:

    latest_message = Subquery(Message.objects.filter(
        conversation_id=OuterRef("id"),
    ).order_by("-date").values('value')[:1])
    
    conversations = Conversation.objects.annotate(
        latest_message=latest_message,
    )
    

    【讨论】:

      【解决方案2】:

      您可以使用prefetch_relatedqueryset 来实现。比如:

      Conversation.objects.prefetch_related(
          Prefetch('messages'),
          queryset=Message.objects.order_by('date').first()
      )
      

      【讨论】:

      • 但是如果会话不包含任何消息,它将失败。我也尝试过latest('date'),但失败并出现错误Message matching query does not exist.
      • 试试:Conversation.objects.prefetch_related(Prefetch('messages'), queryset=Message.objects.exclude(messages__isnull=True).exclude(messages__exact='').order_by('date')[0])
      • 我收到错误 AttributeError: 'Message' object has no attribute '_add_hints,因为它没有返回查询集,因为 ..)[0]
      • 如果不是一直有消息,您可以将[0] 替换为.first()
      • 这还将执行第二个查询 - 子查询解决方案将使用相关子查询执行单个查询以获得所需的值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 2016-02-27
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 2017-05-05
      • 1970-01-01
      相关资源
      最近更新 更多