序列化类常用字段类和字段参数,序列化类高级用法之source,修改序列化字段名字,定制序列化字段的两种方式, 反序列化之数据校验,模型类序列化器(ModelSerializer)的使用,反序列化数据校验源码分析(了解),断言assert
1.序列化类常用字段类和字段参数
# BooleanField BooleanField() # NullBooleanField NullBooleanField() # CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) # EmailField EmailField(max_length=None, min_length=None, allow_blank=False) # RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False) # SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ # URLField URLField(max_length=200, min_length=None, allow_blank=False) # UUIDField UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' # IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options) # IntegerField IntegerField(max_value=None, min_value=None) # FloatField FloatField(max_value=None, min_value=None) # DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数
decimal_palces: 小数点位置 # DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) # DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None) # TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None) # DurationField DurationField() # ChoiceField ChoiceField(choices) choices与Django的用法相同 # MultipleChoiceField MultipleChoiceField(choices) # FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) # ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
*******************************************************以下需要记住并熟练使用**********************************************************************************
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
BooleanField BooleanField()
IntegerField IntegerField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数
decimal_palces: 小数点位置
列表:Listfield :{name:'沸羊羊',age:19,hobby:['健身','美羊羊']}
字典:Dictfield :{name:'沸羊羊',age:19,nowife:{'name':'美羊羊','age':15}}
2.序列化类高级用法
(1)source,修改序列化字段的名字
source可以使返回前端的字段名随意变化,只要在返回前端的字段名中加属性source,使source = ‘字段名’,但是使用source不能使字段名等于前端返回的字段名(就是不能多次一举,闲的没事干),course还可以做跨表查询
想要在前端显示的名字 = serializers.CharField(max_length=32,source='表中字段名')
跨表查询,需要连表
在前端显示的名字 = serializers.CharField(max_length=32,source='表名.前面表名中的字段名')
(2)定制序列化字段的两种方式
方式一
在序列化中用SerializerMethodField(千万别手快点成ModelSerializer)
在serializers.py中的类中加入
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}
如果数据有多条,例如publish.name 有两个就需要使用for循环把他们一个一个取出来在放进一个列表中最后返回
def get_authors(self, obj):
list_authors = []
for author in obj.authors.all():
list_authors.append({'id': author.id, 'name': author.name, 'age': author.age})
return list_authors
方式二
在models中插入
def get_publish(self):
return{'name':self.publish.name,'city':self.publish.city,'email':self.publish.email}
然后在serializers.py类中要加入
get_publish =serializers.DictField()
同上只不过代码换个位置在在serializers中调用
read.only与wirte.only
read.only = Ture read.only是只在返回给前端数据时才会显示 write.only = Ture write.only是前端给后端数据是才会显示
publish = serializers.IntegerField(write_only=True) # publish = serializers.CharField() # authors = serializers.ListField(write_only=True) authors = serializers.ListField(write_only=True) publish_date = serializers.DateField() publish_detail = serializers.DictField(read_only=True) get_authors = serializers.ListField(read_only=True)
上述代码中如果遇到IntegerField和ListField必须要加(write_only=True)不然数据可以存到数据库,但是返回前端的数据会报错显示不出来。同时要从写create,不然也会报错
def create(self, validated_data): res = Book.objects.create(name=validated_data.get('name'), price=validated_data.get('price'), publish_date=validated_data.get('publish_date'), publish_id=validated_data.get('publish'), ) authors = validated_data.get('authors') res.authors.add(*authors) # del validated_data['Publish'] 这是我调试上面问题写的,暂且忽略 return res
3.反序列化之数据校验
数据校验规则跟froms很像,都是先校验自己制定的规则,然后校验局部钩子,最后校验全局钩子
# 这是自己写的规则 name = serializers.CharField(label='书名',required=True,error_messages={ 'required': '书名不能不填'}) price = serializers.DecimalField(label='价格',required=True,max_digits=7, decimal_places=2,error_messages={ 'max_digits':'书太贵了你是来坑钱的吗', 'required': '你这书真的要白送吗'}) publish = serializers.CharField(max_length=8, min_length=3, label='出版社名字', required=True, error_messages={ 'max_length': '出版社名字太长了装不下啦', 'min_length': '你这出版社盗版的嘛,名字那么短', 'required': '这个必填' })
# 局部钩子
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名称中不能有sb')
return name
def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能为66')
return price
# 全局钩子
全局钩子在碰到两次密码校验时会用
def clean(self):
password=self.cleaned_data.get('password')
re_password=self.cleaned_data.get('re_password')
if re_password==password: #校验通过
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')
4.模型类序列化器(ModelSerializer)的使用
与Serializer基本一致,不需要重写create和update方法,就是后面要加Mate,不然会报错,Meta中model要等于序列化表的模型,fields是序列化字段名
class BookSerializer(serializers.ModelSerializer):
name = serializers.CharField(label='书名', max_length=8, min_length=3, error_messages={
'required': '书名不能不填'})
price = serializers.DecimalField(label='价格', required=True, max_value=199, min_value=9, max_digits=7,
decimal_places=2, error_messages={
'max_digits': '书太贵了你是来坑钱的吗',
'required': '你这书真的要白送吗'})
# publish = serializers.IntegerField(write_only=True)
# publish = serializers.CharField(write_only=True)
# authors = serializers.ListField(write_only=True)
authors = serializers.ListField(write_only=True)
publish_date = serializers.DateField()
publish_detail = serializers.DictField(read_only=True)
get_authors = serializers.ListField(read_only=True)
extra_kwargs = {'name': {'max_length': 6},
'publish':{'write_only':True}}
class Meta:
model = Book
fields = ['name', 'price', 'publish', 'authors', 'publish_date', 'publish_detail', 'get_authors']
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名称中不能有sb')
return name
def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能为66')
return price
extra_kwargs
在ModelSerializer中会有一个extra_kwargs,可以给别的字段名加参数
例:
extra_kwargs = {'name':{max_length=6}
5.反序列化数据校验源码分析(了解)
# 先校验字段自己的规则(最大,最小),走局部钩子校验,走全局钩子 # 局部:validate_name,全局叫:validate 为什么? # 入口:从哪开始看,哪个操作,执行了字段校验ser.is_valid() -BaseSerializer内的is_valid()方法 def is_valid(self, *, raise_exception=False): if not hasattr(self, '_validated_data'): try: # 真正的走校验,如果成功,返回校验过后的数据 self._validated_data = self.run_validation(self.initial_data) except ValidationError as exc: return not bool(self._errors) -内部执行了:self.run_validation(self.initial_data)---》本质执行的Serializer的 -如果你按住ctrl键,鼠标点击,会从当前类中找run_validation,找不到会去父类找 -这不是代码的执行,代码执行要从头开始找,从自己身上再往上找 def run_validation(self, data=empty): #局部钩子的执行 value = self.to_internal_value(data) try: # 全局钩子的执行,从根上开始找着执行,优先执行自己定义的序列化类中得全局钩子 value = self.validate(value) except (ValidationError, DjangoValidationError) as exc: raise ValidationError(detail=as_serializer_error(exc)) return value -全局钩子看完了,局部钩子---》 self.to_internal_value---》从根上找----》本质执行的Serializer的 def to_internal_value(self, data): for field in fields: # fields:序列化类中所有的字段,for循环每次取一个字段对象 # 反射:去self:序列化类的对象中,反射 validate_字段名 的方法 validate_method = getattr(self, 'validate_' + field.field_name, None) try: # 这句话是字段自己的校验规则(最大最小长度) validated_value = field.run_validation(primitive_value) # 局部钩子 if validate_method is not None: validated_value = validate_method(validated_value) except ValidationError as exc: errors[field.field_name] = exc.detail return ret # 你自己写的序列化类---》继承了ModelSerializer---》继承了Serializer---》BaseSerializer---》Field
6.断言assert
常规的土鳖写法 list = 'bxf' if 'b' in list: print('有') print('没有') print('完了') 装逼的断言写法 list = 'bxf' assert 'b' in list, '没有' print('完了')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现