Django实现帖子@提及用户的通知及消息管理功能
基于Django的@提及通知可落地实现方案
基础Notification模型定义
不要为了追求通用做过度抽象,直接贴合当前提及通知的需求定义字段即可,参考实现如下:
# notifications/models.py from django.db import models from django.conf import settings from posts.models import Post class Notification(models.Model): NOTIFICATION_TYPES = ( ("mention", "内容提及"), ) # 接收通知的用户 recipient = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="received_notifications" ) # 触发通知的用户(也就是发布内容、提及别人的用户) triggered_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="triggered_notifications" ) # 关联触发通知的具体帖子 related_post = models.ForeignKey( Post, on_delete=models.CASCADE ) # 通知类型,后续扩展评论、点赞通知可以直接加选项 notification_type = models.CharField( max_length=20, choices=NOTIFICATION_TYPES, default="mention" ) # 是否已读标记 is_read = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) class Meta: # 默认按创建时间倒序,最新通知排最前 ordering = ["-created_at"]
@提及匹配与通知生成辅助函数
用轻量正则匹配内容里的@username片段,匹配规则和Django默认User模型的username字段规则保持一致,避免出现匹配到标点、邮箱片段的问题,参考实现:
# notifications/utils.py import re from django.contrib.auth import get_user_model from .models import Notification User = get_user_model() # 匹配规则:@开头,后接字母、数字、下划线,和默认用户名规则对齐 MENTION_PATTERN = re.compile(r"@([a-zA-Z0-9_]+)") def create_mention_notifications(post): # 从帖子内容里提取所有匹配的@片段 mentioned_usernames = MENTION_PATTERN.findall(post.content) # 先对用户名去重,避免同一篇内容里多次@同一个用户生成重复通知 mentioned_usernames = list(set(mentioned_usernames)) for username in mentioned_usernames: # 查找被提及的用户是否真实存在 try: mentioned_user = User.objects.get(username=username) except User.DoesNotExist: continue # 跳过自己提及自己的场景,避免冗余通知 if mentioned_user == post.author: continue # 跳过已经生成过的同内容提及通知,适配用户编辑帖子的场景 if Notification.objects.filter( recipient=mentioned_user, related_post=post, notification_type="mention" ).exists(): continue # 生成正式的通知记录 Notification.objects.create( recipient=mentioned_user, triggered_by=post.author, related_post=post, notification_type="mention" )
通知触发的挂载逻辑
不需要引入复杂的信号、中间件机制,直接在帖子保存的流程里调用辅助函数即可,逻辑直观、调试方便,完全适配简易应用的开发需求。比如在发布帖子的视图里:
# posts/views.py 发布帖子的视图片段 def publish_post(request): if request.method == "POST": form = PostForm(request.POST) if form.is_valid(): post = form.save(commit=False) post.author = request.user post.save() # 帖子保存成功后调用函数生成提及通知 from notifications.utils import create_mention_notifications create_mention_notifications(post) return redirect("post_detail", post_id=post.id)
用户后续编辑帖子的时候,也可以在帖子保存的位置再次调用这个函数,因为函数本身已经做了去重判断,不会产生重复通知。
通知页面视图实现
完全匹配需求:展示当前用户收到的所有通知、统计未读数量、用户访问页面后自动将所有通知标记为已读,参考实现:
# notifications/views.py from django.shortcuts import render from .models import Notification def notification_list(request): # 获取当前登录用户收到的全部通知 user_notifications = Notification.objects.filter(recipient=request.user) # 先统计访问前的未读数量,避免标记已读后未读数为0的问题 unread_count = user_notifications.filter(is_read=False).count() # 批量把未读通知标记为已读 user_notifications.filter(is_read=False).update(is_read=True) return render(request, "notifications/notification_list.html", { "notifications": user_notifications, "unread_count": unread_count })
落地注意事项
- 如果项目自定义的用户名规则支持中文、特殊字符,可以直接调整正则的匹配范围,不要硬套默认规则
- 如果担心匹配到内容里的非提及场景(比如代码块里的@、邮箱地址),可以先过滤掉这部分内容再做匹配,简易应用初期可以先不做这个优化
- 模板里渲染未读数量的时候,直接使用视图传过来的
unread_count变量即可,不要在模板里重复查询数据库
内容的提问来源于stack exchange,提问作者Santiago
相关产品推荐
相关产品推荐

