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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:52:41