DRF嵌套serializer调用is_valid()时尝试创建已有嵌套字段问题排查
问题原因及修复方案
错误根本原因
- JoinRequestSerializer错误嵌套了AccountSerializer和CommunitySerializer。嵌套序列化器在反序列化时会默认对嵌套模型的字段做完整校验,你传入已存在的账号/社区数据会触发Account和Community模型的唯一字段校验;同时AccountSerializer中password是必填的可写字段,序列化已存在Account实例时password不会被包含在返回数据中,因此也会触发password必填的校验错误。
- 序列化器字段配置错误。你给
user和community字段设置了错误的source属性,JoinRequest模型的外键字段本身就叫user和community,不需要额外指定source='account_set'这类反向关联的属性,会导致字段映射完全失效。同时extra_kwargs中社区字段拼写错误为commnuity,相关配置不会生效。 - 字段读写逻辑配置矛盾。你同时将
user和community设置为只读字段,却在构造序列化器时传入这两个字段的data,只读字段会被序列化器在反序列化阶段直接忽略,既不会做校验也不会存入validated_data。 - 单元测试代码逻辑错误。构造测试数据时,Community实例没有调用save()方法持久化到数据库,无法作为外键关联;传入的data中
community字段值是序列化器实例而非序列化后的数据,同时你传入的是完整的用户/社区属性字典,而非关联所需的外键标识。 - JoinRequestSerializer的create方法参数错误。DRF序列化器的create方法要求接收
validated_data作为入参,你定义的def create(self):不符合规范,就算校验通过调用save也会报错。
修复方案
1. 修正JoinRequestSerializer
如果需要在读取JoinRequest时返回嵌套的用户和社区信息,可采用读写分离的字段配置:
class JoinRequestSerializer(serializers.ModelSerializer): # 读场景返回嵌套数据,设为只读 user = AccountSerializer(read_only=True) community = CommunitySerializer(read_only=True) # 写场景用外键ID关联已存在的实例 user_id = serializers.PrimaryKeyRelatedField(queryset=Account.objects.all(), write_only=True, source='user') community_id = serializers.PrimaryKeyRelatedField(queryset=Community.objects.all(), write_only=True, source='community') class Meta: model = JoinRequest fields = ['user', 'community', 'user_id', 'community_id'] validators = [ UniqueTogetherValidator( queryset=JoinRequest.objects.all(), fields=['user_id', 'community_id'], message='该用户已提交过对应社区的加入申请' ) ] def create(self, validated_data): return JoinRequest.objects.create(**validated_data)
如果不需要返回嵌套信息,直接用外键字段即可:
class JoinRequestSerializer(serializers.ModelSerializer): user = serializers.PrimaryKeyRelatedField(queryset=Account.objects.all()) community = serializers.PrimaryKeyRelatedField(queryset=Community.objects.all()) class Meta: model = JoinRequest fields = ['user', 'community'] validators = [ UniqueTogetherValidator( queryset=JoinRequest.objects.all(), fields=['user', 'community'], message='该用户已提交过对应社区的加入申请' ) ]
2. 修正单元测试代码
class JoinRequestSerializerTestCase(TestCase): def test_join_request_serializer_create_success(self): account = register() # 先持久化Community到数据库 community = Community.objects.create(name='CommunityNameExample') # 传外键ID即可 data = {'user_id': account.id, 'community_id': community.id} join_request_serializer = JoinRequestSerializer(data=data) self.assertEqual(join_request_serializer.is_valid(), True) join_request_serializer.save() self.assertEqual(JoinRequest.objects.count(), 1)
内容的提问来源于stack exchange,提问作者William Afonso
相关产品推荐
相关产品推荐

