字段变更触发邮件:投诉状态为Resolved时邮件未发送求助
问题排查与修复方案
核心错误点
状态值判断不匹配
你的Contact模型里STATUS_CHOICE的选项是("1", "Pending")和("2", "Resolved"),这意味着数据库中存储的状态值是"1"或"2",而非显示的文本"Resolved"。信号代码里用instance.status == 'Resolved'判断,永远不会成立,这是邮件未触发的直接原因。信号定义混乱
- 重复定义了两次
send_email_on_status_change接收器,还在第一个接收器内部嵌套了save_status接收器,导致信号注册逻辑混乱,无法正常触发。 - 使用
pre_save信号时未对比实例旧状态,会导致每次保存只要当前状态是Resolved就发邮件,而非仅在状态从其他值变为Resolved时触发。
- 重复定义了两次
无效的
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
相关产品推荐
相关产品推荐

