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

字段变更触发邮件:投诉状态为Resolved时邮件未发送求助

问题排查与修复方案

核心错误点

  1. 状态值判断不匹配
    你的Contact模型里STATUS_CHOICE的选项是("1", "Pending")和("2", "Resolved"),这意味着数据库中存储的状态值是"1"或"2",而非显示的文本"Resolved"。信号代码里用instance.status == 'Resolved'判断,永远不会成立,这是邮件未触发的直接原因。

  2. 信号定义混乱

    • 重复定义了两次send_email_on_status_change接收器,还在第一个接收器内部嵌套了save_status接收器,导致信号注册逻辑混乱,无法正常触发。
    • 使用pre_save信号时未对比实例旧状态,会导致每次保存只要当前状态是Resolved就发邮件,而非仅在状态从其他值变为Resolved时触发。
  3. 无效的save_status函数
    instance.status.save()是错误写法,status是CharField字段,不是模型实例,没有save()方法。


修复后的代码实现

步骤1:优化模型状态定义(可选,提升代码可读性)

如果想让代码更直观,可将STATUS_CHOICE的存储值改为显示文本:

class Contact(models.Model):
    STATUS_CHOICE = (
        ("Pending", "Pending"),
        ("Resolved", "Resolved"),
    )
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=15)
    email = models.EmailField(max_length=254)
    subject = models.CharField(max_length=100)
    status = models.CharField(choices=STATUS_CHOICE, default="Pending", max_length=50)
    created = models.DateTimeField(auto_now_add=True)
    body = models.TextField()

    class Meta:
        ordering = ["-created"]
        verbose_name_plural = "Contacts"

    def __str__(self):
        return f"Message from: {self.name}"

如果不想修改模型存储逻辑,后续信号判断需用"2"代表Resolved状态。

步骤2:正确实现信号接收器

推荐使用post_save信号,且仅在状态变更为Resolved时触发邮件:

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import send_mail
from .models import Contact

@receiver(post_save, sender=Contact)
def send_email_on_status_change(sender, instance, created, **kwargs):
    # 新建实例默认状态为Pending,无需触发邮件
    if created:
        return
    
    # 获取实例修改前的状态
    old_instance = sender.objects.get(pk=instance.pk)
    # 判断状态是否从非Resolved变为Resolved(根据模型定义调整值,原模型用"2",优化后用"Resolved")
    if old_instance.status != "Resolved" and instance.status == "Resolved":
        subject = "投诉状态已更新"
        # 优化邮件内容,展示投诉关键信息
        message = f"您的投诉(提交人:{instance.name},主题:{instance.subject})状态已变更为「已解决」。"
        send_mail(
            subject,
            message,
            'sender@example.com',
            [instance.email],  # 发送给投诉提交用户,替换为固定收件人也可
            fail_silently=False,
        )

步骤3:确保信号正常注册

  • 若信号代码单独放在signals.py中,需在app.py的ready()方法中导入:
    # app/app.py
    from django.apps import AppConfig
    
    class YourAppConfig(AppConfig):
        default_auto_field = 'django.db.models.BigAutoField'
        name = 'your_app_name'
    
        def ready(self):
            import your_app_name.signals
    
  • 确保settings.py配置了正确的邮件后端(以SMTP为例):
    # settings.py
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = 'smtp.example.com'
    EMAIL_PORT = 587
    EMAIL_USE_TLS = True
    EMAIL_HOST_USER = 'sender@example.com'
    EMAIL_HOST_PASSWORD = 'your_email_password'
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:31:03