Django任务管理器:实现单用户通知已读不影响其他用户
解决方案
1. 模型修正
你的TaskAssignee模型中read_by字段属于冗余设计,每个用户与任务的关联只需要独立的read状态即可。修改后模型如下:
class Task(models.Model): created_date = models.DateTimeField(auto_now_add=True, blank=True, null=True) created_by = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, related_name='cb_user_task') name = models.CharField(max_length=255) description = models.TextField() status = models.ForeignKey(TaskStatus, on_delete=models.CASCADE, default=4) priority = models.ForeignKey(TaskPriority, on_delete=models.CASCADE) assigned_to = models.ManyToManyField(User, through='TaskAssignee') completed_date = models.DateTimeField(auto_now_add=False, auto_now=False, blank=True, null=True) updated_date = models.DateTimeField(auto_now_add=False, auto_now=True, null=True, blank=True) updated_by = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, related_name='ub_user_task') def __str__(self): return self.name class TaskAssignee(models.Model): assignee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='t_assignee') task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='a_task') read = models.BooleanField(default=False) # 添加唯一约束,避免同一用户重复分配同一任务 class Meta: unique_together = ('assignee', 'task')
2. 视图逻辑修改
核心问题是之前直接修改了Task实例的状态,导致所有用户的通知被同步变更。现在需要定位到当前用户与任务的关联记录,单独修改其read状态:
from django.http import HttpResponseForbidden from django.db.models import F def task_detail(request, pk): # 验证用户是否有权限查看该任务 try: task = Task.objects.get(id=pk) # 获取当前用户与该任务的关联记录 task_assignee = TaskAssignee.objects.get(task=task, assignee=request.user) except (Task.DoesNotExist, TaskAssignee.DoesNotExist): return HttpResponseForbidden("你无权查看此任务") note_queryset = TaskNote.objects.filter(task_id=task.pk).order_by('-created_date') note_form = TaskNoteForm(request.POST or None) files = TaskFile.objects.filter(task=task) # 仅标记当前用户的任务通知为已读 if not task_assignee.read: task_assignee.read = True task_assignee.save(update_fields=['read']) if request.POST.get("add-note"): if note_form.is_valid(): note = note_form.save(commit=False) note.created_by = request.user note.task = task note.save() return redirect('task_detail', pk=task.pk) # 建议使用URL反向解析,避免硬编码 context = { "task": task, "note_queryset": note_queryset, "note_form": note_form, "files": files, } return render(request, "task_manager/task_detail.html", context)
3. 上下文处理器调整
原逻辑依赖Task的read字段统计未读数量,现在需要关联TaskAssignee模型获取每个用户的独立状态:
def task_notification_processor(request): if request.user.is_authenticated: user = request.user # 获取当前用户的任务,并附带已读状态 user_tasks = Task.objects.filter( taskassignee__assignee=user ).annotate( is_read=F('taskassignee__read') ).order_by('-created_date')[:5] # 统计当前用户的未读任务数量 task_count = TaskAssignee.objects.filter(assignee=user, read=False).count() return { "user_tasks": user_tasks, "task_count": task_count, } else: return {}
关键说明
- 用
TaskAssignee的read字段存储每个用户对任务的独立已读状态,彻底隔离不同用户的通知状态 - 视图中先验证用户权限,再修改对应关联记录的状态,避免越权操作
- 上下文处理器通过关联查询直接统计
TaskAssignee中的未读记录,保证数据准确
内容的提问来源于stack exchange,提问作者fitzkro
相关产品推荐
相关产品推荐

