Django创建用户时自动为自定义UserModel的pbc_id字段赋值
问题原因
你当前把pbc_id的赋值逻辑写在UserManager的创建方法中,只能覆盖主动调用对应manager方法创建用户的场景(比如终端执行createsuperuser命令)。Django Admin创建用户时,部分保存流程不会完整走你在create_user里写的重复赋值逻辑;如果后续有其他代码直接实例化User对象调用save()创建用户,这套逻辑也会失效,最终导致pbc_id为空。
另外你当前代码存在重复调用save()的冗余问题:_create_user里已经做了两次保存,create_user又额外存了一次,会产生不必要的数据库开销。
最优解决方案:使用
post_save信号统一处理 Django的信号机制可以全局监听模型保存事件,不管是从Admin、命令行、API接口、其他业务代码哪个渠道创建用户,只要新用户实例第一次存入数据库生成主键,就会触发赋值逻辑,不会遗漏任何场景。
修改步骤
- 首先清理
UserManager里冗余的pbc_id赋值和重复保存逻辑,简化后代码如下:
class UserManager(BaseUserManager): def _create_user(self, email, password, is_staff, is_superuser, is_candidate, is_voter, **extra_fields): if not email: raise ValueError('Users must have an email address') now = timezone.now() email = self.normalize_email(email) user = self.model( username=email, email=email, is_staff=is_staff, is_active=True, is_superuser=is_superuser, is_candidate=is_candidate, is_voter=is_voter, last_login=now, date_joined=now, **extra_fields ) user.set_password(password) user.save(using=self._db) return user def create_user(self, email, password, **extra_fields): return self._create_user(email, password, False, False, False, False, **extra_fields) def create_superuser(self, email, password, **extra_fields): return self._create_user(email, password, True, True, False, False, **extra_fields)
- 在
models.py中引入post_save信号,编写全局统一的pbc_id赋值逻辑:
from django.db.models.signals import post_save from django.dispatch import receiver # 保留原有User模型代码不变 @receiver(post_save, sender=User) def set_pbc_id(sender, instance, created, **kwargs): # 仅在用户第一次新创建时执行赋值,避免修改用户信息时重复触发 if created and not instance.pbc_id: instance.pbc_id = f"PBC-{instance.pk}" # 只更新pbc_id字段,减少数据库开销,同时避免递归死循环 instance.save(update_fields=['pbc_id'])
可选替代方案:重写模型
save方法 如果不想使用信号,也可以直接在User模型中重写内置的save方法,效果和信号完全一致,可根据个人代码风格选择:
class User(AbstractBaseUser, PermissionsMixin): # 原有所有字段定义保持不变 def save(self, *args, **kwargs): # 标记当前是否为首次创建的新实例 is_new = self._state.adding super().save(*args, **kwargs) # 第一次保存后主键已生成,再赋值pbc_id if is_new and not self.pbc_id: self.pbc_id = f"PBC-{self.pk}" super().save(update_fields=['pbc_id'])
存量数据修复
如果数据库中已经存在pbc_id为空的历史用户,可以在Django shell中执行以下命令批量补全:
from users.models import User for user in User.objects.filter(pbc_id__isnull=True): user.pbc_id = f"PBC-{user.pk}" user.save(update_fields=['pbc_id'])
内容的提问来源于stack exchange,提问作者Neha AK
相关产品推荐
相关产品推荐

