如何为Django序列化器不同字段复用同一验证器?
嘿,这个问题我熟!你想让ChildSerializer里的sister字段复用FatherSerializer中brother的验证逻辑,还得能返回Person对象,之前用自定义验证器没搞定?别担心,有几个实用的方案可以解决:
方案一:提取通用验证方法到父类(最推荐)
把brother字段的验证逻辑抽成一个通用的私有方法,这样父类的brother和子类的sister都能调用,而且后续修改逻辑只需要改一处,代码结构也更清晰:
class FatherSerializer(...): class Meta(object): model = Person fields = ('name', 'email', 'brother') name = serializers.CharField() email = serializers.EmailField() brother = serializers.CharField() def validate_email(self, value): if Person.objects.filter(email=value).exists(): raise serializers.ValidationError('Such email already exists') return value # 提取通用的验证逻辑为私有方法 def _validate_person_exists(self, value): if not Person.objects.filter(name=value).exists(): raise serializers.ValidationError('Such person doesnt exist') return Person.objects.get(name=value) def validate_brother(self, value): return self._validate_person_exists(value) class ChildSerializer(FatherSerializer): class Meta(object): model = Person fields = ('name', 'email', 'sister') sister = serializers.CharField() def validate_sister(self, value): return self._validate_person_exists(value)
方案二:用带工厂函数的自定义验证器(解决你之前的问题)
你之前用validators参数没法返回Person对象,是因为普通验证器函数如果直接传,没处理好返回值逻辑?其实可以写一个工厂函数,返回的验证器函数既能做校验,又能返回查询到的对象:
def person_exists_validator(): def validator(value): if not Person.objects.filter(name=value).exists(): raise serializers.ValidationError('Such person doesnt exist') return Person.objects.get(name=value) return validator class FatherSerializer(...): class Meta(object): model = Person fields = ('name', 'email', 'brother') name = serializers.CharField() email = serializers.EmailField() # 调用工厂函数获取验证器 brother = serializers.CharField(validators=[person_exists_validator()]) def validate_email(self, value): if Person.objects.filter(email=value).exists(): raise serializers.ValidationError('Such email already exists') return value class ChildSerializer(FatherSerializer): class Meta(object): model = Person fields = ('name', 'email', 'sister') # 同样使用这个验证器 sister = serializers.CharField(validators=[person_exists_validator()])
注意这里要调用person_exists_validator()而不是直接传函数名,这样每个字段都会拿到独立的验证器实例,而且验证器会返回查询到的Person对象,完美解决你之前的问题。
方案三:直接调用父类的验证方法(最简洁)
如果sister的验证逻辑和brother完全一致,没有任何差异,那可以直接在子类的validate_sister方法里调用父类的validate_brother:
class ChildSerializer(FatherSerializer): class Meta(object): model = Person fields = ('name', 'email', 'sister') sister = serializers.CharField() def validate_sister(self, value): # 直接复用父类的validate_brother逻辑 return self.validate_brother(value)
内容的提问来源于stack exchange,提问作者akhavro
相关产品推荐
相关产品推荐

