Django信号中无法获取正确is_manager值以创建对应Profile的问题
问题
在Django应用中需要根据user.is_manager的值创建不同的Profile(管理员用户对应Profile1,普通用户对应Profile2),使用post_save信号处理逻辑时遇到异常:
- 已定义两个Profile模型:Profile1用于管理员,Profile2用于普通用户
- 在
managers.py创建管理员用户时,已正确设置user.is_manager=True并保存到数据库 - 但
signals.py的post_save信号处理函数中,instance.is_manager始终返回False,尽管数据库中该字段值正确
相关代码如下:
managers.py
from django.contrib.auth.models import BaseUserManager class UserManager(BaseUserManager): def create_user(self, phone, username, email, password): user = self.model(phone=phone, username=username, email=email) user.set_password(password) user.save(using=self.db) return user def create_superuser(self, phone, username, email, password): user = self.create_user(phone, username, email, password) user.is_admin = True user.is_manager = True # when create a superuser it's a manager too user.save(using=self.db) return
apps.py
from django.apps import AppConfig class PanelConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'panel' def ready(self): import panel.signals
signals.py
from django.db.models.signals import post_save from django.dispatch import receiver from django.conf import settings from .models import User from accounts.models import Profile1, Profile2 @receiver(post_save, sender=User, dispatch_uid="panel.signals.create_profile") def create_profile(sender, instance, created, **kwargs): if created: if instance.is_manager: # this returns False profile = Profile1.objects.create(user=instance) else: profile = Profile2.objects.create(user=instance) profile.save()
解决方案
问题根源
create_superuser方法中,先调用create_user创建并保存了用户(此时is_manager是默认值False),这次保存会触发post_save信号,信号里的instance.is_manager自然是False。之后你修改is_manager为True并再次保存,这时候信号的created参数为False,不满足if created:的判断条件,所以不会重新创建正确的Profile。
两种解决方式
方式一:一次性设置所有字段再保存
避免分两次保存用户,把is_manager和is_admin的设置放到第一次创建时完成,这样只触发一次信号,且信号能拿到正确的字段值:
def create_superuser(self, phone, username, email, password): user = self.model(phone=phone, username=username, email=email) user.set_password(password) user.is_admin = True user.is_manager = True user.save(using=self.db) return user
方式二:修改信号逻辑,支持更新时切换Profile
如果需要保留分两次保存的逻辑,可以修改信号,在用户更新时也检查is_manager的值,自动切换对应的Profile类型:
@receiver(post_save, sender=User, dispatch_uid="panel.signals.create_profile") def create_profile(sender, instance, created, **kwargs): if created: if instance.is_manager: Profile1.objects.create(user=instance) else: Profile2.objects.create(user=instance) else: # 检查现有Profile并切换 if instance.is_manager: Profile2.objects.filter(user=instance).delete() Profile1.objects.get_or_create(user=instance) else: Profile1.objects.filter(user=instance).delete() Profile2.objects.get_or_create(user=instance)
内容的提问来源于stack exchange,提问作者Sajad zarei
相关产品推荐
相关产品推荐

