如何在Django聊天系统中仅显示有消息往来的用户?
Django聊天列表仅展示有消息往来用户的实现方案
1. 确认消息模型结构
首先确保你的models.py中的Message模型包含以下核心字段(如果已有,可跳过此步):
from django.db import models from django.contrib.auth.models import User class Message(models.Model): sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages') receiver = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_messages') content = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-timestamp']
related_name用于反向关联查询,必须设置,后续视图会用到。
2. 修改视图逻辑
在views.py中替换原有的用户查询逻辑,筛选出与当前用户有过消息收发的用户:
from django.shortcuts import render from django.contrib.auth.decorators import login_required from django.db.models import Q, Max from .models import Message from django.contrib.auth.models import User @login_required def chat_list(request): current_user = request.user # 筛选条件:要么当前用户给对方发过消息,要么对方给当前用户发过消息 contacted_users = User.objects.filter( Q(id__in=Message.objects.filter(sender=current_user).values_list('receiver_id', flat=True)) | Q(id__in=Message.objects.filter(receiver=current_user).values_list('sender_id', flat=True)) ).exclude(id=current_user.id).distinct() # 可选:按最后一条消息时间倒序排列,最新聊天优先展示 contacted_users = contacted_users.annotate( last_message_time=Max('sent_messages__timestamp', 'received_messages__timestamp') ).order_by('-last_message_time') return render(request, 'chat/chat_list.html', {'contacted_users': contacted_users})
Q查询实现逻辑或关系,覆盖收发两种场景;distinct()避免同一用户因多次收发消息被重复查询;annotate+Max用于获取双方最后一条消息的时间,实现排序。
3. 调整模板渲染
修改HTML模板(如chat_list.html),遍历筛选后的用户列表:
<h2>聊天列表</h2> <ul class="chat-list"> {% for user in contacted_users %} <li class="chat-item"> <a href="{% url 'chat_detail' user.id %}" class="user-link">{{ user.username }}</a> <!-- 可选:展示最后一条消息预览和时间 --> {% with last_sent=user.sent_messages.first last_received=user.received_messages.first %} {% if last_sent or last_received %} {% if last_sent.timestamp > last_received.timestamp %} <p class="message-preview">{{ last_sent.content|truncatechars:50 }}</p> <small class="message-time">{{ last_sent.timestamp|date:"Y-m-d H:i" }}</small> {% else %} <p class="message-preview">{{ last_received.content|truncatechars:50 }}</p> <small class="message-time">{{ last_received.timestamp|date:"Y-m-d H:i" }}</small> {% endif %} {% endif %} {% endwith %} </li> {% empty %} <li class="empty-state">暂无聊天记录</li> {% endfor %} </ul>
- 替换原有的所有用户遍历逻辑,改为使用
contacted_users; - 可选的消息预览逻辑会对比双方最后一条消息的时间,展示最新的那条。
注意事项
- 如果你的
Message模型中sender/receiver的related_name不是sent_messages/received_messages,需同步修改视图和模板中的对应字段; - 若需要优化性能,可添加数据库索引(如给
sender、receiver、timestamp字段加索引); - 确保视图使用
@login_required装饰器,避免未登录用户访问。
内容的提问来源于stack exchange,提问作者Xrystik
相关产品推荐
相关产品推荐

