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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 13:10:32