Django post_save信号创建Perfil用户档案时first_name、last_name未入库
问题核心
Django信号触发数据库写入操作时,部分字段值未成功存储。
问题描述
在Django项目中使用信号机制,每当内置User模型新增用户注册记录时,自动在Perfil(用户档案)表创建关联的档案记录。目前username关联字段、email字段可正常获取并存储,但first_name、last_name字段始终无法成功赋值。
相关代码
Perfil模型定义
class Perfil(models.Model): username = models.OneToOneField(User, on_delete=models.CASCADE) first_name = models.CharField(max_length=30, verbose_name="first name", blank=True) last_name = models.CharField(max_length=30, verbose_name="last name", blank=True) email = models.EmailField(max_length=75, verbose_name="email address", blank=True) def __str__(self): return self.username.username
new_profile信号实现
def new_profile(sender, instance, created, **kwargs): user_db = User.objects.filter(username__exact=instance).values().first() if created: Perfil.objects.create( username = instance ) Perfil.objects.filter(username__exact=instance).update( first_name = user_db['first_name'], last_name = user_db['last_name'], email = user_db['email'] ) post_save.connect(new_profile, sender=User)
问题补充说明
- 最初尝试在create操作时直接传入所有字段赋值但未生效,改用先创建记录、再执行update更新字段的方案后问题仍未解决。
- 数据库表查询结果显示:email字段正常存储,但last_name、first_name字段为空,问题表现如下:

问题原因与修复方案
根因分析
- 冗余查询逻辑问题:信号回调里传入的
instance就是当前触发保存的User模型实例,完全不需要额外调用User.objects.filter再查一次数据库,多此一举还容易引入匹配错误。 - 字段值本身为空:
post_save信号在User实例第一次写入数据库时触发,绝大多数默认注册流程(比如Django自带的UserCreationForm)首次创建用户时,只会提交username、密码、email字段,first_name、last_name本身就没有赋值,数据库里存的就是空字符串,不管你用create还是update,写进Perfil的自然是空值。 - 缺少后续同步逻辑:就算首次创建时姓名字段为空,后续用户补填个人信息再次保存User时,现有信号逻辑只判断
if created,不会触发Perfil表的字段更新,自然一直是空。
修复代码
from django.db.models.signals import post_save from django.dispatch import receiver from django.contrib.auth.models import User @receiver(post_save, sender=User) def sync_user_perfil(sender, instance, created, **kwargs): if created: # 新建用户时直接从当前实例取字段创建Perfil,无需二次查询、二次更新 Perfil.objects.create( username=instance, first_name=instance.first_name, last_name=instance.last_name, email=instance.email ) else: # 用户后续更新个人信息时,同步更新Perfil对应字段 Perfil.objects.filter(username=instance).update( first_name=instance.first_name, last_name=instance.last_name, email=instance.email )
额外排查点
如果替换上述代码后first_name、last_name依旧为空,直接检查你的注册表单/视图逻辑:确认创建User实例的流程中,是否真的接收并给instance.first_name、instance.last_name赋了值。默认的UserCreationForm没有这两个字段的输入项,如果没自定义表单加字段,创建用户时这两个字段本来就是空值,信号逻辑再正确也拿不到内容。
内容的提问来源于stack exchange,提问作者Gustavo Megazorde
相关产品推荐
相关产品推荐

