
本文介绍如何在 django 模板中将后端查询数据安全、高效地传递给前端 javascript,并通过 dom 操作实现点击发送者标签动态过滤显示对应消息的交互效果。
本文介绍如何在 django 模板中将后端查询数据安全、高效地传递给前端 javascript,并通过 dom 操作实现点击发送者标签动态过滤显示对应消息的交互效果。
要在 Django 应用中实现“点击左侧发送者,右侧仅显示其发送的消息”这一交互功能,核心在于:前后端数据对齐 + 前端精准 DOM 控制。下面提供一套完整、健壮且符合最佳实践的实现方案。
✅ 步骤一:优化后端视图(确保数据可被前端消费)
首先,原视图中 ar_messages_ids 和 unreaded 的逻辑合理,但为支持按发送者筛选,需额外传递每个消息对应的发送者标识(如用户名或 ID),并确保前端能唯一关联消息与发送者:
@authenticated_user
def home(request):
employee = Employee.objects.get(user=request.user)
all_messages = Messages.objects.filter(reciever=request.user).select_related('sender')
# 构建 {sender_id: [message_id, ...]} 映射(可选,用于更复杂逻辑)
# 这里我们采用更轻量的方式:在模板中为每条消息和每个发送者标签设置一致的 data-sender-id
unread_ids = set(all_messages.filter(is_read=False).values_list('id', flat=True))
# 提取所有唯一发送者(避免重复渲染)
senders = {msg.sender for msg in all_messages if msg.sender}
return render(request, "CSM/home.html", {
'employee': employee,
'messages': all_messages,
'unread_ids': unread_ids,
'senders': senders,
'ar_messages_ids': arabic_messages_ids, # 如原有逻辑需保留
})⚠️ 注意:使用 select_related('sender') 避免 N+1 查询;senders 是去重后的 User 对象集合,便于模板中安全遍历。
✅ 步骤二:模板中结构化标记(关键!)
在 home.html 中,左侧发送者列表与右侧消息列表必须使用统一、语义清晰的标识符(推荐 data-sender-id 而非 id 属性,避免 HTML ID 冲突和特殊字符问题):
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
<!-- 左侧:发送者列表 -->
<div class="sender-list">
{% for sender in senders %}
<div class="user" data-sender-id="{{ sender.id }}">
{{ sender.get_full_name|default:sender.username }}
</div>
{% endfor %}
</div>
<!-- 右侧:消息列表 -->
<div class="messages-container">
{% for msg in messages %}
<div class="message-visible"
data-sender-id="{{ msg.sender.id }}"
data-message-id="{{ msg.id }}"
{% if msg.id in unread_ids %}data-unread="true"{% endif %}>
<strong>{{ msg.sender.get_full_name|default:msg.sender.username }}:</strong>
{{ msg.message }}
<small>{{ msg.date_created|timesince }} ago</small>
</div>
{% endfor %}
</div>✅ 优势:data-* 属性天然支持任意字符串(含数字、字母、下划线),无 HTML ID 命名限制;语义明确,利于维护。
✅ 步骤三:JavaScript 实现动态筛选(简洁鲁棒)
使用现代 JS 语法,添加防抖、默认展开、空状态处理等细节:
<script>
document.addEventListener('DOMContentLoaded', function() {
const userElements = document.querySelectorAll('.user');
const messageElements = document.querySelectorAll('.message-visible');
// 默认显示全部消息
messageElements.forEach(el => el.classList.remove('hidden'));
userElements.forEach(userEl => {
userEl.addEventListener('click', function() {
const targetSenderId = this.dataset.senderId;
messageElements.forEach(msgEl => {
const msgSenderId = msgEl.dataset.senderId;
if (msgSenderId === targetSenderId) {
msgEl.classList.remove('hidden');
} else {
msgEl.classList.add('hidden');
}
});
});
});
// 【可选】点击空白区域恢复显示全部
document.addEventListener('click', function(e) {
if (!e.target.closest('.user') && !e.target.closest('.message-visible')) {
messageElements.forEach(el => el.classList.remove('hidden'));
}
});
});
</script>配套 CSS(.hidden 类):
.hidden { display: none !important; }✅ 补充建议与注意事项
- 安全性:始终使用 {{ user.id }}(整数 ID)而非 {{ user.username }} 作为 data-sender-id,避免空格、特殊字符引发 JS 解析错误;
- 性能:若消息量极大(>500 条),建议改用 AJAX 按需加载,而非全量渲染后前端过滤;
- 无障碍:为 .user 元素添加 role="button" 和 tabindex="0",支持键盘操作;
-
用户体验:可增加淡入/滑动动画、加载状态提示、无匹配结果提示(如 暂无此用户消息);
- 扩展性:后续如需多选、搜索、分页,应转向 Vue/React 或 Django REST API + Fetch 方案。
通过以上结构化设计,你不仅实现了基础筛选功能,更构建了可维护、可扩展的前后端协作范式。

















