序列化类常用字段和字段参数 序列化高级用法之source 序列化用户之定制字段的两种方式 多表关联反序列化保存 反序列化字段校验其他 ModelSerializer使用

 

 回顾

1.APIView--->>>drf提供的,继承了原来的View,以后如果写视图类,都继承APIView及其子类
# 2.APIView执行流程
1.去除了csrf认证
2.包装了新的Request对象--->>>视图类中使用的request都是drf的Requset
原来的在哪里呢?--->>>request._request
用起来跟之前一样--->>>__getattr__--->>>学过的魔法方法
request.data--->>>put、post..请求体携带的数据无论是什么编码,都是字典
request.query_params--->>老的request.GET
request.FIELS---跟之前一样,重写了文件类
3.执行了三大认证(认证,权限,频率)--->>在执行视图类的方法之前执行的
4.三大认证的代码,视图方法的代码,如果出现了异常,会有异常捕获--->>>后期会做统一处理
# 3.Request源码分析
# 4.序列化类--->>>APIView+序列化类+Response--->>5个接口
序列化类的作用:做序列化,反序列化,反序列化校验
序列化过程:
写一个序列化类,继承Serializer,写一个个字段CharField,写的字段表示要序列化和反序列化的字段
视图类中:导入,实例化得到对象,对查出来的queryset,单个对象序列化,传入instance参数如果是queryset,一定要传many=True
序列化类对象 ser.data--->>>字典或列表--->>>Response--->>>json格式字符给前端
序列化单条和序列化多条,路由不一样,写成两个视图类,分别是两个get方法

反序列化过程:新增,修改
新增:
前端传入的无论什么编码格式,都在request.data中,是字典
reqeust.data:
urlencoded,form-data--->>QueryDict
json--->>>dict
拿到前端传入的数据,进行反序列化--->>>序列化类的反序列化,完成
序列化类得到对象,传入参数,data=request.data
校验数据
保存:ser.save()--->>>序列化类中重写create方法
修改:
拿到前端传入的数据,进行反序列化,查出要修改的对象--->>>序列化类的反序列化,完成
序列化类得到对象,传入参数,instance=要修改的对象,data=request.data
校验数据
保存:ser.save()--->>序列化类中重写updata方法

# 4.反序列化的校验
只要在序列化类中写局部钩子个全局钩子
局部钩子:
def validata_字段名(self,name):
校验通过,返回name
如果不通过,抛出异常
全局钩子:
# attr,前端传入的数据,走完局部钩子校验后的数据
def validate(self, attrs):
校验通过,返回attrs
如果不通过,抛出异常

# 练习讲解
原生的Django的request中没有data

import json
# 通过装饰器做,装饰器视图函数的,以后都会有request
def wrapper(func):
def inner(request,*args,**kwargs):
# 造个新的request
# 如果是 urlencoded,form-data---->>>request.POST 就有值
# 如果request.POST 就没有值,就是json格式编码
try:
request.data = json.loads(request.body)
except Exception as e:
request.data = request.POST
res = func(request, *args, **kwargs)
return res
return inner

@wrapper # test=wrapper(func)--->以后执行test()本质是--->>>wrapper(func)(request)---本质是inner(request)
def test(request):
print(request.POST) # urlencoded,form-data---->>Queryset
print(requset.data) # 报错
return HttpResponse('ok')

# 总结:前端提交数据的编码格式
urlencoded:
name=wyf&age=18&price=9 放在了请求体中
formdata:
分数据部分和文件部分
'----------------------------585520151165741599946333\r\n
Content-Disposition: form-data;
name="name"\r\n\r\nlqz\r\n
----------------------------585520151165741599946333--\r\n'
json格式:
{"name":"wyf","age":18}

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

常用字段类

 
# 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)

---------记住以下几个-----------
CharField
BooleanField
IntegerField
DecimalField

'''序列化类的额外字段'''
# ListField
ListField(child=,min_length=None,max_length=None)
当hobby下有多个数据时,序列化之后返回的数据格式hobby的部分用列表 ---> ['篮球','足球'] 存储。
{name:'lqz',age:19,hobby:['篮球','足球']}

# DictField
DictField(child=)
序列化之后,使用字典 ---> {'name':'刘亦菲','age':33}{name:'lqz',age:19,wife:{'name':'刘亦菲','age':33}}

常用字段参数

选项参数

 
# 选项参数
给某一些指定的字段使用的参数(不是每个字段都能使用这些参数)


# 给CharField字段类以及其子类(EmailField)使用的参数
参数名称		    作用
max_length	    最大长度
min_lenght	    最小长度
allow_blank	    是否允许为空
trim_whitespace	    是否截断空白字符


# 给IntegerField字段类使用的参数
max_value	    最小值
min_value	    最大值

通用参数

 
# 通用参数:放在哪个字段类上都可以的
参数名称			作用
required	  	表明该字段在反序列化时必须输入,默认True
default	   	 	反序列化时使用的默认值(字段如果没传,就是默认值)
allow_null	   	表明该字段是否允许传入None,默认False
validators	   	该字段使用的验证器【不需要了解】
error_messages		包含错误编号与错误信息的字典
label		       	用于HTML展示API页面时,显示的字段名称
help_text	   	用于HTML展示API页面时,显示的字段帮助提示信息

# 重点
read_only		表明该字段仅用于序列化输出,默认False
			    (从数据库拿出来,给前端)
write_only		表明该字段仅用于反序列化输入,默认False
			(前端往后端传入数据)
   
# 如何理解这里的read\write
站在程序的角度:
从数据库拿数据(序列化) 			--->  读
从前端获取数据,写入数据库(反序列化)	--->

上述参数用于反序列化校验数据(类似form组件):

validators参数(了解):

给validators传入一个列表,列表中存放函数的内存地址。用这些函数来进行数据校验。

总结:

 
# 校验流程:
字段参数限制(max_length) ---> validators函数校验 ---> 局部钩子 ---> 全局钩子

# 有钩子函数,为什么要使用validators?
钩子函数只能在当前类生效,而validators的校验函数,可以在多个类生效,无需写重复的代码

序列化类高级用法之source

source用于修改序列化字段的名字。

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

# 需求:name字段在前端显示的时候叫book_name
-使用source,字段参数,可以指定序列化的是模型表中得哪个字段
    	book_name = serializers.CharField(max_length=8, min_length=3,source='name')
-source指定的可以是字段,也可以是方法,用于重命名
-source可以做跨表查询

'''
1. source反应了该序列化字段的数据来源。
2. source(来源)表示该序列化字段book_name,对应的是后端的哪一个字段(name)
3. 给序列化类传入了一个模型表Book的对象,在这里序列化类和模型表建立了联系。所以使用source参数,可以指定序列化字段的数据来源是模型表的哪个字段。
'''

source参数可以填写三个东西。

source填写类中字段

视图类:

序列化类:

序列化类中字段和model类中的字段需要一一对应:

可以使用source指定一个model类中字段,表示序列化这个字段。
当序列化类中字段变量名与source参数值相同时,此时会报错:

source填写模型类中方法

model类中写函数:

可以使用source指向模型类中的方法,方法的返回值会被序列化。


序列化某个方法。

source支持跨表查询

如果这里的publish是一对多外键字段,该外键在图书类。可以通过publish.name跳转到出版社,序列化出版社的名字。

代码:

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

定制序列化字段的两种方式

准备工作

表创建:

 
from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(null=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name

    # 写了个方法,可以包装成数据属性,也可以不包
    def publish_de(self):
        return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}

    def author_li(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 Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    # def __str__(self):
    #     return self.name

publish是外键字段。

如果这里写CharField,那么前端得到的序列化结果是什么?

可见结果是字符串:

这是因为我们写了__str__:

如果我们将__str__注释掉,前端将会得到:

如果我们不在模型类中写__str__,则需要使用source跨表查询:

无论是__str__,还是source参数,都只能给前端返回出版社的某一个属性(名称|城市|邮箱)。

而我们希望返回一个字典对象,可以包含出版社的所有信息,如下:

 
# 前端显示形式
{
        "name": "西游记",
        "price": 33,
        "publish": {name:xx,city:xxx,email:sss}
}

实现该需求(定制序列化)有以下两种方法。

方法一:使用SerializerMethodField

 
# 第一种:在【序列化类】中写SerializerMethodField
    publish = serializers.SerializerMethodField()
    def get_publish(self, obj):
        # obj 是当前序列化的对象
        return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}

这里我们不使用CharField,因为CharField是用于序列化字符串形式,而我们是想要序列化对象形式的数据。

使用SerializerMethodField:

需要配合一个方法使用,这个方法的返回值是什么,前端接收的publish就是什么。

get_publish方法需要传入一个参数obj,这个obj是当前序列化的对象:


通过book对象进行跨表查询,获取出版社的各个字段数据。

出版社对象是用字典。(一个出版社对应一个字典)(由于一本书只有一个出版社,所以使用字典)

更多示例:

由于一本书可以有多个作者,所以我们返回一个列表,列表中是一个个作者对象。

方法二:在模型类中写方法

 
# 第二种:在【表模型】中写方法(又多一些)  
    def publish_detail(self):
        return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}
    在序列化中取
    publish_detail=serializers.DictField()

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

也就是在表模型中写一个方法,与序列化类中的字段重名:

总结:序列化类不仅仅能序列化模型类中某个字段,还能序列化模型类中的方法。这种方法和上面方法的实际区别就是,将同一段代码写在不同的位置,写在序列化类或者写在模型表。

这里如果我们序列化类使用charfield字段,会造成postman无法美化显示Json字典:

这里是因为,我们模型类中方法返回的是一个字典,而CharField是用于序列化字符串,所以会直接将字典强行转化成字符串(如上图所示,该字典是用单引号引起来的,不是JSON格式)。

所以这里应该使用DictField:

实现显示所有作者:

在模型类中写函数,返回作者列表。

方式一代码演示:使用SerializerMethodField

 
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.IntegerField(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):
        # obj 是当前序列化的对象
        return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}

    # 练习,用方式一,显示所有作者对象  []
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        res_list = []
        for author in obj.authors.all():
            res_list.append({'id': author.id, 'name': author.name, 'age': author.age})
        return res_list

方式二代码演示:在表模型中写(用的最多)

 
# 表模型中
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(null=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    # 写了个方法,可以包装成数据属性,也可以不包
    def publish_detail(self):
        return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}

    def author_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.CharField(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)

在模型类中写逻辑代码的行为(逻辑不写在视图类中),称之为ddd(领域驱动模型)。
相关文章:
https://cloud.tencent.com/developer/article/1371115

关系表外键字段的反序列化保存

多表关联情况下的新增图书接口:(request.data接收前端发送的数据)

我们要新增图书,除了上传普通字段,还要上传外键字段。
需要在前端上传出版社主键和作者列表(列表中是作者主键)。

注意:需要在序列化类中重写create方法。

前端提交的数据

前端提交常见问题:

无法在新增图书的时候新增出版社,publish字段只能写出版社的主键。而作者和作者详情表可以一同新增。

前端的提交数据应该是这样的:

前端示例:

序列化类添加字段

实现反序列化需要在序列化类中添加新字段:

这两个反序列化的字段,对应着模型类中的外键字段:

添加write_only、read_only参数:

如果不添加这些参数,则可能会出现一个字段既参与序列化,又参与反序列化的情况:

查看前端接收到的序列化结果:

这里是自动把序列化类中的字段全部都序列化了。
publish在数据库中没有对应的字段,所以这里展现给前端的是一个对象。

重写create方法

当前我们实现反序列化还需要重写序列化类的create、updata的方法。

 
# 缺点
	1 在序列化中每个字段都要写,无论是序列化还是反序列化
    2 如果新增或者修改,在序列化类中都需要重写create或update
    
# 解决这个缺点,使用ModelSerializer来做

代码:

 
# 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): 
            # validated_data 校验过后的数据  
              {"name":"三国1演义",
                "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

序列化类继承ModelSerializer

继承ModelSerializer:

modelserializer是跟表有关联的。

Meta类

在BookmodelSerializer中写一个Meta类:

model=Book: 指定序列化的是哪个模型类
fields='__all__': 指定序列化哪些字段,双下all表示序列化模型类所有字段。

修改视图层,使用ModelSerializer:

查看结果:

可以发现把publish、authors的序列化结果是主键值,而我们希望能获取出版社对象和作者对象,所以需要自己定制如何序列化。

自定义序列化字段

方法一:使用serializerMethodField


修改Meta类的fields:

在fields列表里填写,我们serializermethodfield产生的字段

添加read_only:

给authors和publish添加write_only属性:

在Meta类写extra_kwargs。你在字典里写的键值对,会当做字段参数传入字段类。

代码:

 
class BookModelSerializer(serializers.ModelSerializer): #ModelSerializer继承Serializer
    # 不需要写字段了,字段从表模型映射过来
    class Meta:
        model = Book  # 要序列化的表模型
        # fields='__all__' # 所有字段都序列化
        fields = ['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.SerializerMethodField(read_only=True)
	 ...
   author_list = serializers.SerializerMethodField(read_only=True)
	...

刚刚我们是使用了自定义序列化的第一种方式:在序列化类中使用SerializerMethodField。

方法二:在模型类中写方法

Meta类中的fields列表支持写入以下几种:

  1. 模型类中的字段
  2. 模型类中的方法
  3. 序列化类中的字段(SerializerMethodField)

在表模型内写方法:

在field字段注册:

在field字段注册模型类中的方法时,就不存在添加参数read_only了,因为这两个方法没有对应的字段。如果是方法一,则可以给SerializerMethodField字段添加参数。

ModelSerializer使用总结

 
#  如何使用
1 定义一个类继承ModelSerializer
2 类内部写内部内 class Meta:
3 在内部类中指定model
		填写要序列化的表
4 在内部类中指定fields
		写要序列化的字段,写__all__表示所有,__all__不包含方法,如果要包含方法必须要在列表中写一个个字段。
		示例:['字段1''字段2'...]
5 在内部类中指定extra_kwargs,给字段添加字段参数的
		因为有些字段是从模型类映射过来的,在序列化类中没有这个字段,所以需要使用extra_kwargs添加字段参数。
6 在序列化类中,可以重写某个字段,优先使用你重写的
        name = serializers.SerializerMethodField()
    	def get_name(self, obj):
        	return 'sb---' + obj.name
 
7 以后不需要重写create和update了
    	-ModelSerializer写好了,兼容性更好,任意表都可以直接存(考虑了外键关联)
    	-当有特殊需求的情况下,也可以重写

在序列化类中,可以重写某个字段,优先使用你重写的:

这里我们在序列化类中,将name字段写了两次,此时会优先用上面的。
正常情况下会直接输出书名,我们进行重写,可以给查询到的结果做一些操作再输出给前端。
也就是说:即可以在fields里面注册某个字段,也可以手动重写字段。

查看效果:

反序列化之数据校验

反序列化的数据校验和forms组件很像。既有字段自己的校验规则,也有局部钩子、全局钩子。

字段自己的校验规则

 
# 字段自己的校验规则
-如果继承的是Serializer	
    因为序列化类中有字段,所以可以直接添加字段参数。

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

    
-如果继承的是ModelSerializer,有两种方式:
	1. 在Meta类上面重写字段
	2. 使用Meta类extra_kwargs给字段添加字段参数

    extra_kwargs = {
    'name': {'max_length': 8, 'min_length': 3}, 'error_messages': {'min_length': "太短了"},
    }        

    注意:只能添加模型类字段包含的字段参数。	

钩子函数

 
# 局部钩子
    -如果继承的是Serializer,写法一样
    -如果继承的是ModelSerializer,写法一样
    
	def validate_name(self, name):
        if name.startswith('sb'):
            # 校验不通过,抛异常
            raise ValidationError('不能以sb卡头')
        else:
            return name
    注意:局部钩子不要写在Meta类中。

        
# 全局钩子
	-如果继承的是Serializer,写法一样
    -如果继承的是ModelSerializer,写法一样
	def validate(self, attrs):
        if attrs.get('name') == attrs.get('publish_date'):
            raise ValidationError('名字不能等于日期')
        else:
            return attrs
        
 '''当以上校验全部通过,序列化类的is_valid才会通过'''

局部钩子:

form组件局部钩子函数示例: clean_name
反序列化校验局部钩子示例:validate_name
二者只是有名字上的区别。

反序列化数据校验源码分析(了解)

 
# 校验顺序
先校验字段自己的规则(最大,最小),走局部钩子校验,走全局钩子

# 疑问
局部钩子:validate_name,全局钩子:validate 
为什么钩子函数必须这样命名?

# 入口
从哪开始看源码,哪个操作执行了字段校验 ---> ser.is_valid()

# 序列化类的继承顺序
你自己写的序列化类 ---> 继承了ModelSerializer ---> 继承了Serializer ---> BaseSerializer ---> Field
'''一直往上查找is_valid,发现在BaseSerializer里有,如下只挑选is_valid最关键的代码'''


1. BaseSerializer内的is_valid()方法

	    def is_valid(self, *, raise_exception=False):
            '''省略'''
            # 如果没有进行校验,对象中就没有_validated_data
            if not hasattr(self, '_validated_data'):
                try:
                    # 真正进行校验的代码,如果校验成功,返回校验过后的数据 
                    self._validated_data = self.run_validation(self.initial_data) 
			       # 这里的self.run_validation运行的是Serializer类的,而不是Field类的。
                except ValidationError as exc:
            return not bool(self._errors)
    
说明:self.run_validation(self.initial_data)这行代码执行的是Serializer的run_validation
    	-补充说明:如果你按住ctrl键,鼠标点击,会从当前类中找run_validation,找不到会去父类找
    	-这不是代码的执行,代码执行要从头开始找,从自己身上再往上找(对象方法的查找顺序)
        
        
2.查看Serializer中的run_validation:
        
    	    def run_validation(self, data=empty):
                # 局部钩子的执行
                value = self.to_internal_value(data)
                try:
                    # 全局钩子的执行,从根上开始找着执行,优先执行自己定义的序列化类中得全局钩子
                    value = self.validate(value)
                except (ValidationError, DjangoValidationError) as exc:  # 注意这里还能捕获django抛出的异常
                    raise ValidationError(detail=as_serializer_error(exc))

                return value
  -全局钩子看完了,局部钩子---》 self.to_internal_value---》从根上找----》本质执行的Serializer的

3.查看Serializer中的to_internal_value

     def to_internal_value(self, data):
        for field in fields: # fields:序列化类中所有的字段,for循环每次取一个字段对象
            # 反射:去self:序列化类的对象中,反射 validate_字段名 的方法
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            # field.field_name 获取字段对象的字段名称(字符串)
            try:
                # 这句话是字段自己的校验规则(最大最小长度),执行的是field的run_validation
                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
    
字段对象是什么:	name=serializers.CharField(max_length=8,min_length=3,error_messages={'min_length': "太短了"})	
这里的name就是一个字段对象。具体可以研究OMR怎么实现关系表映射。


查看源码的设置

添加这个设置可以进行前进、回退等操作。

断言assert

 
# 框架的源码中,大量使用断言

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

# 土鳖写法
# name = 'lqz1'
# if not name == 'lqz':
#     raise Exception('name不等于lqz')
#
# print('程序执行完了')

# assert的断言写法
name = 'lqz1'
assert name == 'lqz', 'name不等于lqz'
print('程序执行完了')
posted @   小福福  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
  1. 1 原来你也在这儿 温余福
  2. 2 世间美好和你环环扣扣 温余福
  3. 3 随风起舞 温余福
  4. 4 罪恶都市 温余福
随风起舞 - 温余福
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 米果

作曲 : 高橋優

编曲 : 刘胡轶/貢多杰

制作人 : 刘胡轶/吴青峰

配唱制作人 : 刘胡轶

乐器监制 : 刘胡轶

吉他 : 胡晨

贝斯 : 甯子达

弦乐录音棚 : 中国剧院录音棚

录音工程师 : 倪涵文/李游/李杨/邢铜/韩宽/李巍

录音监制 : 倪涵文/李游

混音&母带工作室 : OKmastering studio

混音&母带工程师 : 全相彦

制作协力 : 刘西洋

制作发行 : 智慧大狗 × 天才联盟

出品人 : 张葛

监制 : 崔恕/王明宇

弦乐监制 : 李朋

弦乐 : 国际首席爱乐乐团

鼓(打击乐):祁大为

和音编写&演唱:鱼椒盐

人声&吉他&鼓(打击乐)录音棚:55Tec studio

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

这一路上走走停停

这一路上走走停停

顺着少年漂流的痕迹

迈出车站的前一刻

竟有些犹豫

不禁笑这近乡情怯

不禁笑这近乡情怯

仍无可避免

而长野的天

依旧那么暖

风吹起了从前

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

逆着光行走 任风吹雨打

短短的路走走停停

短短的路走走停停

也有了几分的距离

不知抚摸的是故事 还是段心情

也许期待的不过是 与时间为敌

再次看到你

微凉晨光里

笑得很甜蜜

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

晚风吹起你鬓间的白发

晚风吹起你鬓间的白发

抚平回忆留下的疤

你的眼中 明暗交杂 一笑生花

我仍感叹于世界之大

我仍感叹于世界之大

也沉醉于儿时情话

不剩真假 不做挣扎 无谓笑话

我终将青春还给了她

连同指尖弹出的盛夏

心之所动 就随风去了

以爱之名 你还愿意吗

点击右上角即可分享
微信分享提示