Master Ref ID在详情表中功能异常问题排查求助
Django嵌套创建ChargeBackReason及关联详情时的异常排查与解决
问题现象
- 未传入
master_ref_id时,接口返回400错误,提示'master_ref_id字段必填',但该字段应由系统自动关联主表记录,无需手动传入; - 手动传入
master_ref_id时,触发TypeError,提示'master_ref_id参数重复赋值'。
测试用POST请求数据
{ "name": "name3", "action_id": 1, "reason_items": [ { "attachement_format_id": 1 } ] }
问题根源
- 子序列化器校验逻辑错误:
ChargeBackReasonDetailsSerializer使用fields = '__all__',会包含模型中必填的master_ref_id外键字段,序列化器会强制要求前端传入该字段,导致未传时报错; - 参数重复赋值冲突:手动传入
master_ref_id后,ChargeBackReasonSerializer的create方法中又通过**item, master_ref_id = reason给该字段赋值,触发参数重复的TypeError。
解决方案
1. 修改子序列化器,排除master_ref_id字段
因为master_ref_id由主表创建后自动关联,不需要前端传入,所以在子序列化器中排除该字段:
# serializer.py class ChargeBackReasonDetailsSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) class Meta: model = ChargeBackReasonDetails # 显式指定需要的字段,排除master_ref_id fields = ['id', 'attachement_format_id', 'created_by', 'updated_by', 'updated_date_time'] # 或者使用exclude方式 # exclude = ['master_ref_id']
注意:如果views中给子表数据添加了
created_by等字段,需确保序列化器包含这些字段,否则validated_data会丢失对应值。
2. 优化主序列化器的create方法
确保创建子表记录时,不会出现参数重复赋值:
# serializer.py class ChargeBackReasonSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) reason_items = ChargeBackReasonDetailsSerializer(many=True) class Meta: model = ChargeBackReason fields = '__all__' def create(self, validated_data): item_row = validated_data.pop('reason_items') reason = ChargeBackReason.objects.create(**validated_data) for item in item_row: # 此时item中无master_ref_id,直接关联主表实例 ChargeBackReasonDetails.objects.create(master_ref_id=reason, **item) return reason
3. 补全模型缺失字段(可选)
从views代码看,系统会给记录添加created_by、updated_by、updated_date_time字段,需确保模型中存在这些字段:
# models.py from django.contrib.auth.models import User class ChargeBackReason(models.Model): action_id = models.ForeignKey(ChargeBackAction, verbose_name="action_id", on_delete=models.PROTECT) name = models.CharField(max_length=100,verbose_name='name') created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='chargeback_reason_created') updated_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='chargeback_reason_updated') updated_date_time = models.DateTimeField(auto_now=True) class ChargeBackReasonDetails(models.Model): master_ref_id = models.ForeignKey(ChargeBackReason, verbose_name="Master Ref Id",related_name="reason_items",on_delete=models.PROTECT) attachement_format_id = models.ForeignKey(AllMaster,verbose_name="Attachement Format",on_delete=models.PROTECT) created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='chargeback_detail_created') updated_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name='chargeback_detail_updated') updated_date_time = models.DateTimeField(auto_now=True)
4. 简化视图层逻辑(可选)
将created_by等字段的赋值逻辑移到序列化器中,让视图更简洁:
# views.py def create(self, request): with transaction.atomic(): serializer = ChargeBackReasonSerializer(data=request.data) if serializer.is_valid(): serializer.save(created_by=request.user, updated_by=request.user) return Response({STATUS: RECORD_CREATED}, status=status.HTTP_201_CREATED) else: return Response({STATUS: status.HTTP_400_BAD_REQUEST, MESSAGE: serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
同时修改序列化器create方法,传递用户信息到子表:
def create(self, validated_data): item_row = validated_data.pop('reason_items') reason = ChargeBackReason.objects.create(**validated_data) user_info = { 'created_by': validated_data['created_by'], 'updated_by': validated_data['updated_by'] } for item in item_row: ChargeBackReasonDetails.objects.create(master_ref_id=reason, **item, **user_info) return reason
内容的提问来源于stack exchange,提问作者Purushottam Nawale
相关产品推荐
相关产品推荐

