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

Django通知功能异常:新建工单无法显示对应提示

问题描述

在Django项目中开发了通知功能,其余功能正常,但模板无法根据操作展示对应消息:新建工单时,始终显示“工单已更新”,而非预期的“新工单已分配给你”。


模板代码

<div class="dropdown-content" id="myDropdown">
          {% if notifications %}
            {% for notification in notifications %}
              {% if notification.notification_type == 'created' %}
                <a href="#">{{notification.ticket.name}}: A new ticket has been assigned to you.</a>
              {% else %}
                <a href="#">{{notification.ticket.name}}: The ticket has been updated.</a>
              {% endif %}
            {% endfor %}
          {% else %}
            <a href="#">No new notifications</a>
          {% endif %}
</div>

通知模型(models.py)

class Notification(models.Model):
    OPTIONS = (
        ('created', 'created'),
        ('updated', 'updated'),
    )
    
    recipient = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name='notifications')
    ticket = models.ForeignKey(Ticket, on_delete=models.SET_NULL, null=True, related_name='notifications')
    message = models.TextField()
    notification_type = models.CharField(choices=OPTIONS, max_length=15, null=True)
    is_read = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

通知信号(signals.py)

@receiver(post_save, sender=Ticket)
def create_notification(sender, instance, created, **kwargs):
    if created:
        notification_type = 'created'
    else:
        notification_type = 'updated'
        
    assignees = instance.assignee.all()
    for assignee in assignees:
        Notification.objects.create(recipient=assignee, notification_type=notification_type)

创建工单视图(views.py)

@login_required
def createTicket(request):
    form = TicketForm()
    
    categories = Category.objects.all()
    users = CustomUser.objects.all()
    if request.method == 'POST':
        category_name = request.POST.get('category')
        category, created = Category.objects.get_or_create(name=category_name)
        
        # Retrieve the project object that the ticket should be connected with
        project_id = request.POST.get('project')
        project = Project.objects.get(id=project_id)
        
        # Retrieve the list of selected users from the form
        assignee_ids = request.POST.getlist('assignee')
        assignee = CustomUser.objects.filter(id__in=assignee_ids)
        
        ticket = Ticket.objects.create(
            host = request.user,
            category=category,
            project=project,
            name=request.POST.get('name'),
            status=request.POST.get('status'),
            priority=request.POST.get('priority'),
            type=request.POST.get('type'),
            description=request.POST.get('description'),
        )
        
        # Add the selected users to the ticket
        ticket.assignee.set(assignee)
        ticket.save()
        
        return redirect('ticket', pk=ticket.id)
    
    context = {'form': form, 'categories': categories, 'users': users}
    return render(request, 'tickets/ticket_form.html', context)

问题排查

  1. 二次触发post_save信号:创建工单时,ticket.assignee.set(assignee)后手动调用ticket.save(),会再次触发Ticket的post_save信号,此时created=False,生成updated类型通知。而第一次创建ticket时,assignee尚未设置,信号中instance.assignee.all()为空,不会创建通知,最终用户看到的是第二次生成的updated通知。
  2. 通知未关联工单:创建Notification时未指定ticket=instance,导致通知与工单无关联,模板中{{notification.ticket.name}}可能出现异常。
  3. 必填字段未赋值:Notification模型的message字段为必填项,但创建时未传入该参数,会引发数据库保存错误。

修复方案

1. 修改创建工单视图(views.py)

移除ticket.assignee.set(assignee)后的ticket.save(),因为set()方法会自动保存多对多关联关系,无需手动调用save():

@login_required
def createTicket(request):
    form = TicketForm()
    
    categories = Category.objects.all()
    users = CustomUser.objects.all()
    if request.method == 'POST':
        category_name = request.POST.get('category')
        category, created = Category.objects.get_or_create(name=category_name)
        
        project_id = request.POST.get('project')
        project = Project.objects.get(id=project_id)
        
        assignee_ids = request.POST.getlist('assignee')
        assignee = CustomUser.objects.filter(id__in=assignee_ids)
        
        ticket = Ticket.objects.create(
            host = request.user,
            category=category,
            project=project,
            name=request.POST.get('name'),
            status=request.POST.get('status'),
            priority=request.POST.get('priority'),
            type=request.POST.get('type'),
            description=request.POST.get('description'),
        )
        
        ticket.assignee.set(assignee)
        # 移除多余的ticket.save()
        
        return redirect('ticket', pk=ticket.id)
    
    context = {'form': form, 'categories': categories, 'users': users}
    return render(request, 'tickets/ticket_form.html', context)

2. 修改通知信号(signals.py)

补充工单关联和message字段赋值:

@receiver(post_save, sender=Ticket)
def create_notification(sender, instance, created, **kwargs):
    if created:
        notification_type = 'created'
        message = f"A new ticket has been assigned to you."
    else:
        notification_type = 'updated'
        message = f"The ticket has been updated."
        
    assignees = instance.assignee.all()
    for assignee in assignees:
        Notification.objects.create(
            recipient=assignee, 
            ticket=instance,  # 关联工单
            notification_type=notification_type,
            message=message  # 赋值必填字段
        )

3. 可选:模板消息本地化(中文)

将模板中的英文消息替换为中文:

<div class="dropdown-content" id="myDropdown">
          {% if notifications %}
            {% for notification in notifications %}
              {% if notification.notification_type == 'created' %}
                <a href="#">{{notification.ticket.name}}: 新工单已分配给你。</a>
              {% else %}
                <a href="#">{{notification.ticket.name}}: 工单已更新。</a>
              {% endif %}
            {% endfor %}
          {% else %}
            <a href="#">暂无新通知</a>
          {% endif %}
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:15:43