Django信号报错:Notification.user需为CustomUser实例的解决方案
问题描述
尝试为Django应用实现通知系统,要求创建Invitation模型实例时,向对应的CustomUser发送通知。但Invitation模型没有且不想新增user字段,当前信号代码执行时报错:
Cannot assign "<Invitation: Adamu>": "Notification.user" must be a "CustomUser" instance.
现有信号代码
from django.db.models.signals import post_save from django.dispatch import receiver from django.conf import settings from .models import Level, Notification, Invitation from django.urls import reverse User = settings.AUTH_USER_MODEL @receiver(post_save, sender=Invitation) def comment_post_save(sender, instance, **kwargs): message = f'{instance.first_name} has booked our"{instance.select_type.level} room"' link = reverse('Open-Room', args=[str(instance.select_type.slug)]) notification = Notification(user=instance, message=message, link=link) notification.save()
现有模型代码
class Invitation(models.Model): first_name = models.CharField(max_length=40) last_name = models.CharField(max_length=40) id_card = models.CharField(max_length=50, choices=ID_CARD) id_number = models.CharField(max_length=100) nationality = models.CharField(max_length=50, choices=LIST_OF_COUNTRY) state = models.CharField(max_length=50) town = models.CharField(max_length=50) address = models.CharField(max_length=90) phone_number = models.IntegerField() guardian_phone_number = models.IntegerField() number_of_day = models.IntegerField() visited_for = models.CharField(max_length=40, choices=VISITED_FOR_THIS) date_created = models.DateTimeField(auto_now_add=True) select_type = models.ForeignKey(LevelType, on_delete=models.CASCADE) slug = models.SlugField(unique=True) def save(self, *args, **kwargs): if not self.slug: # generate a random 15-character string random_string = ''.join(random.choices(string.ascii_lowercase + string.digits, k=15)) self.slug = f"{slugify(self.nationality)}-{random_string}" super().save(*args, **kwargs) def __str__(self): return str(self.first_name) class Notification(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) message = models.TextField() link = models.URLField(blank=True, null=True) read = models.BooleanField(default=False) class LevelType(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) name = models.CharField(max_length=20)
解决方案
核心问题是信号代码错误地将Invitation实例赋值给Notification.user字段,而该字段要求接收CustomUser类型的实例。
观察模型关联关系可知:Invitation通过select_type外键关联到LevelType,而LevelType本身已关联CustomUser。因此可以通过这条关联链获取目标用户,无需给Invitation新增user字段。
修改后的信号代码如下:
from django.db.models.signals import post_save from django.dispatch import receiver from django.conf import settings from .models import Level, Notification, Invitation from django.urls import reverse User = settings.AUTH_USER_MODEL @receiver(post_save, sender=Invitation) def comment_post_save(sender, instance, **kwargs): # 通过LevelType关联获取对应的CustomUser实例 target_user = instance.select_type.user # 修正原代码中可能的笔误(LevelType模型无level字段,替换为name) message = f'{instance.first_name} has booked our "{instance.select_type.name}" room' link = reverse('Open-Room', args=[str(instance.select_type.slug)]) notification = Notification(user=target_user, message=message, link=link) notification.save()
内容的提问来源于stack exchange,提问作者Adamu Abdulkarim Dee
相关产品推荐
相关产品推荐

