Django向/users/profiles发POST请求报IntegrityError唯一约束冲突
问题根因
报错触发的核心原因是你自定义的User模型继承了Django自带的AbstractUser,但没有显式移除默认的username字段,该字段自带唯一约束:
你创建User实例时没有给username字段赋值,默认存入空字符串,第一条用户数据生成后,后续再创建新用户都会因为重复存入空字符串的username触发唯一键冲突。
修复步骤
- 移除User模型默认的username字段
在你的User类中显式将username设为None,覆盖父类的同名字段:
- 移除User模型默认的username字段
class User(AbstractUser): # 新增这一行,删除默认username字段 username = None # 原有代码保持不变 GENDER_CHOICES = [ (0, 'Female'), (1, 'Male'), ] phone_nm = models.CharField(max_length=11, unique=True) # ...其余原有字段和逻辑
- 修正ProfileSerializer逻辑
你原代码中将related_user设为了read_only=True,导致序列化器校验后的数据里不会包含关联用户信息,同时create方法中直接调用User.objects.create没有走你自定义的create_user逻辑,会导致密码不加密、必填字段校验失效的问题:
- 修正ProfileSerializer逻辑
class ProfileSerializer(serializers.ModelSerializer): # 去掉read_only=True,允许嵌套写入用户数据 related_user = UserSerializer() jobs = JobSerializer(required=False, many=True, allow_null=True, read_only=True) class Meta: model = Profile fields = ['related_user', 'nickname', 'introduction', 'jobs', 'recomms_cnt'] def create(self, validated_data): related_user_data = validated_data.pop('related_user') # 调用自定义的create_user方法,自动处理密码加密、字段校验 related_user = User.objects.create_user(**related_user_data) profile = Profile.objects.create(related_user=related_user, **validated_data) # 按需设置默认岗位 if not profile.jobs.exists(): profile.jobs.add(Job.objects.get(pk=1)) return profile
- 修正视图逻辑
你原代码中手动调用validate、create方法属于错误用法,DRF序列化器的is_valid会自动执行校验逻辑,调用save()方法会自动触发create/update逻辑:
- 修正视图逻辑
@csrf_exempt def post(self, request): serializer = ProfileSerializer(data=request.data) if serializer.is_valid(raise_exception=True): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- 执行数据库迁移
完成上述修改后,生成并执行迁移文件,删除User表中原有username字段:
- 执行数据库迁移
python manage.py makemigrations python manage.py migrate
注意:如果数据库中已有存量数据,建议先备份数据再执行迁移,避免数据丢失。
额外优化建议
- 你自定义User模型中存在
login_PW字段,和AbstractUser自带的password字段功能重复,且直接存储明文密码存在严重安全风险,建议删除login_PW字段。 - Profile模型中
related_user的related_name设置为related_user不符合语义,建议改为profile,方便通过User实例反向查询关联的Profile数据:user.profile即可获取对应的Profile对象。
内容的提问来源于stack exchange,提问作者hyowon
相关产品推荐
相关产品推荐

