drf3-序列化常用字段类-字段参数-高级用法-source-两种定制方式-数据校验-模型类序列化-断言

  • 序列化类常用字段类和字段参数
  • 序列化类高级用法之source,修改序列化字段名字
  • 序列化高级用法之定制序列化字段的两种方式、
  • 反序列化之数据校验
  • 模型类序列化器(ModelSerializer)的使用
  • 反序列化数据校验源码分析(了解)
  • 断言assert

序列化类常用字段类和字段参数

常用字段类

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'"5ce0e9a55ffa654bcee01238041fb31a" 3'int' - 如: "123456789012312313134124512351145145114" 4'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
-------------------------------------------------------------------------------------------------------------------------------
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)

经常记的

CharFiled

BoleanField

IntegerField

DecimalField

常用字段参数

给CharFiled字段类使用的参数

#选项参数:
参数名称	作用
max_length 最大长度
min_length  最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符

integerField字段类使用的参数

max_value  最小值

min_value   最大值

通用参数

放在任何一个字段类使用都可以

required    表明该字段在反序列化时必须输入,默认True
default       反序列化使用的默认值

序列化高级用法

source

序列化高级用法之source,,修改序列化字段名字

source 用于重命名, 针对的可以是字段可以是方法,
source可以做跨表查询

#获取所有图书接口,APIView + Response + 序列化类

#name 字段在前端显示的时候叫book_name
	-使用source,字段参数,可以指定序列化表中得那个字段
	     book_name  = serializers.CharFiled(max_length=8,min_length=3,source='name')

1.1代码演示

class BookSerializer(serializers.Serializer)
	name_detail = serializers.CharFiled(max_length=8,min_length=3,source='name')
	#或
	publish_name =serializers.CharField(max_length=8,min_length=3,souce='publish.name')
	#或
	xx = serializers.CharFiled(max_length=8,min_length=3,source='xx') #source的xx表示模型中得方法

两种定制序列化的方式

#前端显示形式
{
        "name": "西游记",
        "price": 33,
        "publish": {name:xx,city:xxx,email:sss}
}
---------------------------------------第一种:在序列化类中写SerializerMethodField------------------------
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
	#obj是当前序列化的对象
	return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}


--------------------------------------第二种:在表模型中写方法----------------------------------------
def publish_detail(self):
	return {'name':self.publish.name,'city':self.publish.city,'email':self.publish.email}

#在模型中写逻辑代码,称之为ddd,领域驱动模型

2.1代码演示方式1:在序列化类中使用serializerMethodField

class BookSerializer(serializers.Serializer):
	name = serializers.CharFiled(max_length=8,min_length=3)
	price = serializers.CharFiled(min_value=10,max_value=99)
	publish_date = serializers.DateField()
	#publish要序列化成(name:北京出版社,city:北京,email:2@qq.com)
	#方式一:SerializerMethodField必须配合一个方法(get_字段名,需要接受一个参数,方法返回什么,字段就是什么)
	publish = serializers.SerializerMethodField()
	def get_publish(self,obj):
		return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}
	
	#练习,用方式一,显示所有作者对象
	authors = serilizers.SerializerMethodField()
	def get_authors.all(self,obj):
		res_list = []
		for author in obj.authors.all():
			res_list.append({'id':author.id,'name':author.name})
		return res_list.append

2.2代码演示方式二:

#表模型中
class  Book(models.Model):
	name = models.CharField(max_length=32)
	price = models.DecimalField(max__digits=5,decimal_palces=2)
	publish_date = models.DateField(null=True)
	publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
	authors =modesl.ManyToManyField(to='Author')
	
	#写了个方法,可以包装成数据属性,也可以不包
	def publish_detail(self):
		return {'name':self.publish.name,'city':self.publish.city,'email':self.publish.email}
		
	def auth_list(self):
		res_list = [] 
		for author in self.authors.all():
			res_list.append({'id':author.id,'name':author.name,'age':author.age})
		return res_list

序列化类中

class BookSerializer(serializers.Serializer):
	name  = serializers.CharFiled(max_length=8,min_length=3)
	price = serializers.IntegerField(min_value=10,max_value=99)
	publish_date = serializers.DateField()
	
	#方式二: 在表模型中写方法
	publish_detail = serializers.DictField(read_only=True)
	# 练习,使用方式二实现,显示所有作者
	author_list = serializers.ListField(read_only=True)

2.3 有关联关系表的反序列化的保存

#1.序列化字段和发序列化字段不一样【序列化类中】
#	反序列化用的
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
#序列化用的
publish_detail =serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)

#2.一定要重写create 【序列化中】
	def create(self,validated_data):
	#validata_data 校验过后的数据
	{ "name":"三国""price":19,
	"publish_date": "2022-09-27",
	"publish":1,
	"authors":[1,2]
		}
	book  = 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')
	book.authors.add(*authors)
	return book

2.4 使用继承Serializer 的序列化类保存需要重写的create方法

#缺点

​ 1.在序列化中每个字段都要写,无论序列化还是反序列化
​ 2.如果新增或者修改,在序列化类中,都需要重写create或者update

解决这个缺点,使用ModelSerializer 来做

反序列化之数据校验

跟forms很像

forms 
	-字段自己的校验规则
	-局部钩子
	-全局钩子

字段自己的校验规则

如果继承的是Serializer写法如下。

name = serializers.CharField(max_length=8,min_length=3,error_messages={'min_length':"太短了"})

如果是继承的ModelSerializer,写法如下

extra_kwargs ={

​ 'name':{'max_length':8,'min_length':3,'errors_messages':{"min_length":"太短了"}},}

局部钩子

​ -如果继承的是serializer,写法一样

​ -如果继承的是ModelSerializer,写法一样

 	def valid_name(self,name):
	if name.startwith('sb'):
#校验不通过,抛出异常
		raise ValidationError(不能以sb开头)
	else
		return name                  #返回

全局钩子

​ 如果继承的是Serializer,写法一样

​ 如果继承的是ModelSerializer,写法一样

	def validate(self,attrs):
	if  attrs.get('name') == attrs.get(publish_date):
		raise  ValidationError('名字不能等于日期')
	else:
		return attrs

模型类序列化器(ModelSerializer)使用

class BookModelSerializer(serializers.ModelSerializer):   #ModelSerializer继承Serializer
#不需要写字段了,字段从表模型映射过来
	class Meta:
		model =Book    #要序列化的表模型
		#field = '__all__' #所有字段都序列化
		field = ['name','price','publish_date','publish','authors','publish_detail','author_list'] 列表中有什么,就是序列化那个字段
		#给authors和publish加write_only属性
		#name加max_len属性
		extra_kwargs = {
            	'name':{'max_length':8},
            	'publish':{'write_only':True},
            	'authors':{'write_only':True},
		}
	publish_detail = serializers.SeriazerMethodField(read_only=True)
		....
	author_list = serializers.SerializerMethodField(read_only =True)
	       ....

4.1总结

#如何使用
	1.定义一个类继承ModelSerializer
	2.类内部写内部类 class Meta:
	3.在内部类中指定序列化model(要序列化的表)
	4.在内部类中指定fields(要序列化的字段,写__all__表示所有,不包含方法,写[一个个字段])
	5.在内部类中指定extra_kwargs, 给字段添加字段参数的
	6.在序列化类中,可以重写某i个字段,优先使用你重写的
		name = serializers.SerializerMethorField()
			def get_name(self,obj):
				return 'sb---' + obj.name
	7. 以后不需要重写create 和update了
		-ModelSerializer写好了,兼容性更好,任意表都可以直接存。

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

断言 assert

框架中,大量使用断言

assert 断言的作用,判断,比如,断定一个变量必须是xx,如果不是就报错

name = lzl
assert name == 'zl123','name不等于lzl'
print('执行完毕')
----------------------------------------
执行结果:
如果name = lzl 打印执行完毕,不等于,抛出异常打印 name不等于lzl

posted @   名字长的像一只老山羊  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 我与微信审核的“相爱相杀”看个人小程序副业
点击右上角即可分享
微信分享提示