You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django聊天室模型:获取用户所属所有房间的最新消息

解决指定用户所属聊天室最新消息的SQL查询与Django ORM实现

一、SQLite查询解决方案

你原有的查询能获取所有房间的最新消息,但缺少筛选指定用户所属房间的条件。可以通过以下两种方式修改:

方式1:使用EXISTS筛选用户所属房间

SELECT cm.*, ma.*, cmb.*
FROM chat_message AS cm
INNER JOIN (
    SELECT room_id, MAX(id) AS lm 
    FROM chat_message 
    GROUP BY room_id
) AS last_messages ON last_messages.lm = cm.id
INNER JOIN main_advertisement ma ON cm.advertisement_id = ma.id
INNER JOIN chat_membership AS cmb ON cm.room_id = cmb.id
-- 判断该房间是否存在目标用户的消息(即用户属于该房间)
WHERE EXISTS (
    SELECT 1 
    FROM chat_message AS user_msg 
    WHERE user_msg.room_id = cmb.id 
      AND user_msg.user_id = 3
)
ORDER BY cm.created_at DESC;

方式2:使用DISTINCT ON直接取每个房间最新消息

SQLite支持DISTINCT ON语法,可以按房间分组后取最新的消息记录:

SELECT DISTINCT ON (cm.room_id) 
       cm.id, cm.message, cm.created_at, cm.user_id,
       ma.*, cmb.room_name
FROM chat_message AS cm
INNER JOIN main_advertisement ma ON cm.advertisement_id = ma.id
INNER JOIN chat_membership AS cmb ON cm.room_id = cmb.id
-- 关联目标用户的消息记录,筛选出用户所属的房间
INNER JOIN chat_message AS user_msg ON user_msg.room_id = cmb.id AND user_msg.user_id = 3
-- 按房间分组,再按消息创建时间倒序,确保每个房间第一条是最新消息
ORDER BY cm.room_id, cm.created_at DESC;

二、Django ORM实现提示

方法1:从Membership模型出发,关联最新消息

from django.db.models import Subquery, OuterRef, Max, F
from django.db.models.query import Prefetch
from .models import Message, Membership, CustomUser

# 获取目标用户
target_user = CustomUser.objects.get(id=3)

# 子查询:获取每个房间的最新消息ID
latest_msg_subquery = Message.objects.filter(
    room=OuterRef('pk')
).values('room').annotate(latest_id=Max('id')).values('latest_id')

# 筛选用户所属房间,同时关联最新消息
rooms_with_latest_msg = Membership.objects.filter(
    # 通过Message表关联,筛选用户参与的房间
    message__user=target_user
).annotate(
    latest_message_id=Subquery(latest_msg_subquery)
).prefetch_related(
    # 预取最新消息及其关联的广告、用户,避免N+1查询
    Prefetch(
        'message_set',
        queryset=Message.objects.filter(id=F('latest_message_id')).select_related('advertisement', 'user'),
        to_attr='latest_message'
    )
).distinct()  # 去重,确保每个房间只返回一条记录

# 遍历结果示例
for room in rooms_with_latest_msg:
    print(f"房间名称:{room.room_name}")
    if room.latest_message:
        latest_msg = room.latest_message[0]
        print(f"最新消息内容:{latest_msg.message}")
        print(f"发送者:{latest_msg.user.username}")
        print(f"发送时间:{latest_msg.created_at}")

方法2:直接从Message模型筛选最新消息

from django.db.models import Subquery, OuterRef
from .models import Message, CustomUser

target_user = CustomUser.objects.get(id=3)

# 子查询:获取每个房间的最新消息
latest_msg_subquery = Message.objects.filter(
    room=OuterRef('room')
).order_by('-created_at')[:1]

# 筛选用户所属房间的最新消息,去重后每个房间一条记录
user_latest_msgs = Message.objects.filter(
    room__message__user=target_user
).annotate(
    latest_msg_content=Subquery(latest_msg_subquery.values('message')),
    latest_msg_sender=Subquery(latest_msg_subquery.values('user__username')),
    latest_msg_time=Subquery(latest_msg_subquery.values('created_at')),
    room_name=Subquery(latest_msg_subquery.values('room__room_name'))
).values(
    'room_name', 'latest_msg_content', 'latest_msg_sender', 'latest_msg_time'
).distinct('room__id')

# 遍历结果示例
for item in user_latest_msgs:
    print(f"房间名称:{item['room_name']}")
    print(f"最新消息:{item['latest_msg_content']}")
    print(f"发送者:{item['latest_msg_sender']}")
    print(f"时间:{item['latest_msg_time']}")

内容的提问来源于stack exchange,提问作者gary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:12:46