Django DRF创建Package时触发唯一约束重复键值错误求助
解决DRF ListCreateAPIView创建实例时主键重复且重复创建的问题
先查序列化器的字段配置
- 检查你的
PackageSerializer,如果序列化器里包含了id(即pk)字段,且没有设置为只读,前端请求时如果携带了id值,或者序列化器在创建逻辑中手动赋值了id,就会导致DRF尝试用指定的id创建实例,和数据库序列冲突。 - 修复方式:在序列化器的
Meta类里把id设为只读字段:
class PackageSerializer(serializers.ModelSerializer): class Meta: model = Package fields = ['id', 'name'] # 假设你需要返回id字段 read_only_fields = ['id'] # 关键:创建时不允许传入id,由数据库自动生成
检查视图的create方法是否重复执行创建逻辑
- 如果你重写了
ListCreateAPIView的create方法,确认有没有不小心执行了两次创建操作——比如既调用了perform_create,又手动调用了Package.objects.create()。 - 错误示例:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) # 第一次创建 Package.objects.create(**serializer.validated_data) # 第二次重复创建 headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
- 修复:删除多余的创建代码,保留DRF默认的创建逻辑即可,或者确保只执行一次创建操作。
排查信号/中间件的干扰
- 检查项目中有没有注册
post_save这类信号,或者自定义的中间件,是否在实例创建时触发了额外的创建逻辑,导致重复插入数据。 - 测试方法:暂时注释掉信号和自定义中间件,重新调用API,如果问题消失,再逐步定位是哪个组件引发的。
数据库序列重置(终极方案)
- 如果你确认没有代码层面的重复创建,那可能是数据库序列和实际数据不一致,针对PostgreSQL(从错误信息判断是该数据库),手动执行以下SQL:
-- 查看当前序列的下一个值 SELECT nextval('exam_package_id_seq'); -- 将序列值重置为当前表中最大id+1 SELECT setval('exam_package_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM exam_package));
注意:exam_package_id_seq是默认的序列名,若你的表序列名不同,需要替换为实际名称(可通过\d exam_package在psql中查看)。
内容的提问来源于stack exchange,提问作者Pexicade
相关产品推荐
相关产品推荐

