Django注册表单提交时触发IntegrityError(非空约束失败)问题求助
嗨,我仔细看了你的问题和代码,这个错误的根源很清晰:你在创建用户的时候,第一次保存用户实例时phone_number字段是空的,而数据库里这个字段被设置为非空约束,所以触发了IntegrityError。下面给你拆解问题原因和具体的解决办法:
问题根源分析
你的views.py里,调用Account.objects.create_user()的时候,这个方法内部已经执行了user.save()(看你的MyAccountManager里的代码),但此时user的phone_number字段还没有被赋值——你是在create_user之后才设置user.phone_number = phone_number再save(),但这一步已经晚了,第一次save()的时候数据库就会检查phone_number的非空约束,直接抛出错误。
另外你的models.py里phone_number字段定义是models.IntegerField(),没有设置null=True或blank=True,所以数据库层面强制要求这个字段必须有值。
解决办法(推荐第一种)
方法1:修改用户管理器,让create_user直接接收并赋值phone_number
这是最规范的做法,让用户创建时就带上所有必填字段:
- 先修改
models.py里的MyAccountManager的create_user方法:
class MyAccountManager(BaseUserManager): def create_user(self, first_name, last_name, username, email, phone_number, password=None): if not email: raise ValueError('user must have an email address ') if not username: raise ValueError('user must have an username ') # 新增手机号非空校验 if not phone_number: raise ValueError('user must have a phone number ') user = self.model( email = self.normalize_email(email), username = username, first_name = first_name, last_name = last_name, phone_number = phone_number, # 新增:创建实例时直接赋值手机号 ) user.set_password(password) user.save(using=self._db) return user # 同步修改create_superuser方法,让它也能传递phone_number def create_superuser(self, first_name, last_name, email, username, phone_number, password): user = self.create_user( email= self.normalize_email(email), username = username, password = password, first_name = first_name, last_name = last_name, phone_number = phone_number, # 新增传递这个参数 ) user.is_admin = True user.is_active = True user.is_staff = True user.is_superadmin = True user.save(using=self._db) return user
- 然后修改
views.py里的调用代码,直接把phone_number传给create_user:
# 替换原来的create_user调用 user = Account.objects.create_user( first_name = first_name, last_name = last_name, email = email, username = username, password = password, phone_number = phone_number # 新增传递这个参数 ) # 这里就不需要再写user.phone_number = phone_number和user.save()了
方法2:临时允许phone_number为空(不推荐,除非业务允许)
如果暂时不想修改管理器,也可以先修改模型字段,允许它暂时为空,之后再赋值:
修改models.py里的phone_number字段:
phone_number= models.IntegerField(null=True, blank=True)
然后运行python manage.py makemigrations和python manage.py migrate更新数据库。不过这种方法会导致数据库里可能存在phone_number为空的用户,不符合业务要求的话不建议使用。
额外的小建议
手机号用IntegerField其实不太合适:
- 手机号可能包含前置零(比如某些地区的号码),用数字类型会丢失前置零
- 部分地区的手机号长度可能超过数据库
INT类型的限制(比如MySQL的INT最大支持10位数字,11位手机号需要用BigIntegerField) - 手机号是标识,不是用来做数值计算的,更适合用字符串存储
所以建议把phone_number改成CharField:
phone_number = models.CharField(max_length=20) # 20位足够存带区号的手机号
备注:内容来源于stack exchange,提问作者Web Extol College

