【问题标题】:django query: stuck trying to display only one instance of the model per iddjango 查询:卡住尝试只显示每个 id 模型的一个实例
【发布时间】:2023-01-22 19:49:43
【问题描述】:

我正在为 django 应用程序编写一个对话模块,但我在构建一个显示每个对话的侧边菜单时拼命失败:

  • 收件人姓名
  • 对话中的最后一条消息
  • 最后一条消息的时间戳

我正在努力编写准确的查询。

conversations = ChatRoom.objects.filter(building=building.building_id, participants__in=[user]).prefetch_related(
        'participants','chat_set').order_by('-chat__timestamp')

此查询的问题在于它为每条消息返回一个聊天室对象,因此在模板中有以下代码:

<ul class="flex flex-col space-y-1 mt-4 -mx-2 overflow-y-auto" style="height:300px">
    <h2 class="my-2 mb-2 ml-2 text-lg text-gray-600">Chats</h2>
    {% for convo in conversations %}
            <li>
          {% if convo.chat_set.last.content %}
                {% for participant in convo.participants.all %}
                    {% if participant.id != request.user.id %}
                        <a href="{% url 'room' room_id=convo.id %}"
                            class="flex items-center px-3 py-2 text-sm transition duration-150 ease-in-out border-b border-gray-300 cursor-pointer hover:bg-gray-100 focus:outline-none">

                            <div class="w-10 h-10 rounded-full border-2 border-black flex justify-center items-center m-2">

                                <span> {{ participant.username|first|upper }}</span>
                            </div>

                            <div class="w-full pb-2">
                                <div class="flex justify-between">

                                    <span class="block ml-2 font-semibold text-gray-600"> {{ participant.username }}</span>

                                    <span class="block ml-2 text-sm text-gray-600">{{ convo.chat_set.last.timestamp}}</span>
                                </div>

                                <span class="block ml-2 text-sm text-gray-600">{{ convo.chat_set.last.content  }}</span>
                            </div>
                        </a>
                    {% endif %}
                {% endfor %}
            </li>
        {% for %}
    {% endfor %}
</ul>

每发送一条消息显示一行,而不是每次对话显示一行,其中包含最新消息。

老实说,我不知道如何在后端修改查询(尝试 dinstinct() 方法不起作用,我也没有找到一种方法来改变我在前面的内容,以便每次对话只显示一个项目。

欢迎任何帮助,如果需要,我可以分享更多信息。

【问题讨论】:

    标签: python django


    【解决方案1】:

    您可以在查询中使用 annotate() 方法来获取每个对话的最新消息,然后在您的模板中使用它来显示信息。以下是如何修改查询的示例:

    from django.db.models import Max
    
    conversations = ChatRoom.objects.filter(building=building.building_id, participants__in=[user]) 
                                    .prefetch_related('participants', 'chat_set') 
                                    .annotate(latest_message=Max('chat_set__timestamp')) 
                                    .order_by('-latest_message')
    

    annotate() 方法允许您向查询集中添加一个新字段,该字段由提供的表达式计算得出。在本例中,我们添加了一个名为 latest_message 的新字段,该字段是通过获取对话中所有消息的最大时间戳计算得出的。

    然后在您的模板中,您可以使用 convo.latest_message 访问最新消息的时间戳,并使用 convo.chat_set.last.content 访问最新消息的内容。

    您还可以在查询中使用 distinct() 方法来消除重复结果,如下所示:

    conversations = ChatRoom.objects.filter(building=building.building_id, participants__in=[user]) 
                                    .prefetch_related('participants', 'chat_set') 
                                    .annotate(latest_message=Max('chat_set__timestamp')) 
                                    .order_by('-latest_message') 
                                    .distinct()
    

    您还可以使用 values() 方法按对话分组并选择最大时间戳,然后在您的模板中使用它。

    conversations = ChatRoom.objects.filter(building=building.building_id, participants__in=[user]) 
                                    .prefetch_related('participants') 
                                    .values('id') 
                                    .annotate(latest_message=Max('chat_set__timestamp')) 
                                    .order_by('-latest_message') 
    

    在这种情况下,您将不得不使用“id”字段来获取对话的其他字段。

    我希望这有帮助!

    【讨论】:

      猜你喜欢
      • 2016-12-25
      • 1970-01-01
      • 2019-01-25
      • 2011-09-08
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多