如何解决使用Django嵌套序列化器时出现的Integrity Error?
问题描述
使用Django嵌套序列化器创建Job数据时触发IntegrityError,错误提示NOT NULL constraint failed: naukriapp_job.company_id。
错误详情
Django Version: 4.1.3
Exception Type: IntegrityError
Exception Value: NOT NULL constraint failed: naukriapp_job.company_id
Exception Location: D:\naukri\naukrienv\lib\site-packages\django\db\backends\sqlite3\base.py, line 357, in execute
Raised during: naukriapp.views.Jobviewset
Python Executable: D:\naukri\naukrienv\Scripts\python.exe
当前使用的JobSerializer代码
class JobSerializer(ModelSerializer): company = CompanySerializer(read_only=True) skills = SkillSerializer(many=True, read_only=True) class Meta: fields = ['title', 'description', 'max_salary', 'min_salary', 'employment_type', 'max_experience', 'min_experience', 'company', 'location', 'industry_type', 'skills'] model = Job
问题原因
company = CompanySerializer(read_only=True)的配置导致序列化器在**反序列化(创建/更新数据)**时忽略该字段,但Job模型中company_id是必填字段(带有NOT NULL约束),创建Job时未传入company_id,因此数据库抛出完整性错误。
解决方案
场景1:关联已存在的Company
若创建Job时只需关联已有的Company,无需嵌套创建新Company,可添加company_id字段用于接收输入,保留嵌套的company字段用于序列化输出:
class JobSerializer(ModelSerializer): company = CompanySerializer(read_only=True) # 添加company_id字段,仅用于写入关联的公司ID company_id = serializers.PrimaryKeyRelatedField( queryset=Company.objects.all(), write_only=True ) skills = SkillSerializer(many=True, read_only=True) class Meta: fields = ['title', 'description', 'max_salary', 'min_salary', 'employment_type', 'max_experience', 'min_experience', 'company', 'company_id', 'location', 'industry_type', 'skills'] model = Job
创建Job时,前端只需传入company_id的值即可完成关联,返回数据时会自动嵌套输出Company的详细信息。
场景2:创建Job时同时嵌套创建Company
若需要在创建Job的同时生成新的Company,需去掉read_only=True,并重写create方法处理嵌套对象的创建逻辑:
class JobSerializer(ModelSerializer): company = CompanySerializer() skills = SkillSerializer(many=True, read_only=True) class Meta: fields = ['title', 'description', 'max_salary', 'min_salary', 'employment_type', 'max_experience', 'min_experience', 'company', 'location', 'industry_type', 'skills'] model = Job def create(self, validated_data): # 提取嵌套的company数据 company_data = validated_data.pop('company') # 创建Company对象 company = Company.objects.create(**company_data) # 创建Job并关联新创建的Company job = Job.objects.create(company=company, **validated_data) return job
注意:此场景下前端需传入完整的Company必填字段数据,才能成功创建Company对象。
额外提示
若更新Job时出现相同错误,逻辑类似:要么传入company_id更新关联关系,要么重写update方法处理嵌套Company的更新操作。
内容的提问来源于stack exchange,提问作者Ravi chandra

