切入点:url.py中的.as_view()
方法
path('test/',views.TestView.as_view()),
path
的第二个参数是:View
类的as_view内
部有个view
闭包函数内存地址
一旦有请求来了,匹配test
路径成功
执行第二个参数view
函数内存地址(requset)
本质执行了self.dispatch(request)
通过反射去获得方法(如果是get
请求,就是get
方法)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
执行get方法,传入参数
handler(request, *args, **kwargs)
与CBV的源码分析过程一样,我们也是从路由中的as_view()
作为切入点
path('test/',APIView类的as_view内部是用了View的as_view内的view闭包函数),
path的第二个参数是:APIView
类的as_view
内的view闭包函数
一旦请求来了,匹配test
路径成功
执行第二个参数view函数内存地址(requset)
,其实是执行View
的as_view
内的view
闭包函数,但是加了个csrf_exempt
装饰器
所以,继承了APIView
的所有接口,都没有csrf
的校验了(************************************)
执行self.dispatch(request)
----》APIView
类的
def dispatch(self, request, *args, **kwargs):
# 以后所有的request对象,都是****新的request对象***,它是drf的Request类的对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
try:
#整个drf的执行流程内的权限,频率,认证
self.initial(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
# 全局异常
response = self.handle_exception(exc)
# 响应
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
'''
### request = self.initialize_request(request, *args, **kwargs)
##返回的request对象是drf Request类的request对象
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
### *******以后,在视图类中使用的request对象已经不是原来的request对象了,现在都是drf的request对象了
request
对象变成了新的request
对象,drf
的request
对象django.core.handlers.wsgi.WSGIRequest
drf
的request
对象:rest_framework.request.Request
self._request
图解:
request
对象, 从中取出想要的数据# 正常取值应该是使用 "_request"
request._request.method
# 但我们使用的却是
request.method
.
属性会触发 类的__getattr__
方法__getattr__
def __getattr__(self, attr):
try:
# 去原生的request反射属性
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
在 Response 类中找到 __getattr__
, 当属性在 drf 中的 request 中找不到时, 就会通过反射的方式从原生的 request 对象中取值
虽然视图类中request对象变成了drf的request,但是用起来,跟原来的一样,只不过它多了一些属性
request.data
:post
请求提交的数据,不论什么格式,都在它中requst.query_params
:get
请求提交的数据(查询参数)drf的request对象用起来跟原来一样(重写了__getattr__)
request.data #post请求提交的数据,不论什么格式,都在它中
requst.query_params# get请求提交的数据(查询参数)
python
中的对象转成json
格式字符串json
格式字符串转成python
中的对象反序列化, 把客户端发送过来的数据,经过 request 以后变成字典, 序列化器可以把字典转成模型
反序列化, 完成数据校验功能
[序列化类的对象].data
获取序列化后的字典ps:: 如果不使用rest_framework提供的Response,就得使用JsonResponse
from django.db import models
class Book2(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
price = models.IntegerField(max_length=8)
author = models.CharField(max_length=16)
publish = models.CharField(max_length=16)
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from drf_test import models
# 定义一个序列化器,继承ModelSerializer
class BookSerializer2(serializers.Serializer):
# 里面书写想要序列化的字段,想序列哪个就书写哪个
title = serializers.CharField()
price = serializers.IntegerField()
from rest_framework.viewsets import ModelViewSet
from drf_test.serializers import BookSerializer2
from drf_test import models
class Book2View(APIView):
def get(self,request,id):
# 从数据库中获取到Book的对象
book_obj = models.Book2.objects.filter(nid=id).first()
# 将book_obj放进我们写的序列化器里面进行序列化
book_ser = BookSerializer2(book_obj)
# [序列化对象].data就是序列化后得到的字典
return Response(book_ser.data)
re_path('^books/(?P\d+)' , views.Book2View.as_view()),
字段 | 字段构造方式 |
---|---|
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) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
参数 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
参数 | 作用 |
---|---|
max_value | 最小值 |
min_value | 最大值 |
参数 | 作用 |
---|---|
read_only(最重要) | 表明该字段仅用于序列化输出,默认False |
write_only(最重要) | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
写一个序列化的类,继承Serializer;如果要反序列化,继承了Serializer,必须重写create方法。
def create(self, validated_data):
res = models.Publish.objects.create(**validated_data)
return res
在类中写要反序列化的字段,想反序列化哪个字段,就在类中写哪个字段,字段的属性
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值
在视图类中使用,导入自定义的继承继承Serializer类的序列化类,把要要修改的对象传入,得到序列序列化对象
数据校验if publish_ser.is_valid():
如果校验通过,就保存
如果不通过,返回restful
规范的返回结果
如果字段的校验规则不够,可以写钩子函数(局部和全局)
def post(self, request):
publish_ser = serializer.PublishSerializer(data=request.data)
if publish_ser.is_valid():
# 直接保存,保存到哪个表里?需要重写save
publish_ser.save()
return Response(publish_ser.data)
else:
print(publish_ser.errors)
return Response('数据有问题啊')
is_valid()
方法进行校验# 在视图类中书写
class PublishView(APIView):
# 新增数据方法
def post(self,request):
# 传入前端提交的json格式数据,拿到反序列化的对象
publish_ser = serializer.PublishSerializer(data=request.data)
# 使用 is_valid() 方法进行数据校验,返回 True 和 False
if publish_ser.is_valid():
# 手动保存
# 拿到创建的对象
res = modeels.Publish.objects.create(**publish_ser.validated_data)
# 将其赋值给instance
publish_ser.instance = res
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
.save()
方法来实现保存.save()
方法明确规定必须重写该方法如果继承了
Serializer
, 但凡是数据的新增还是更新, 调用.save()
方法进行数据保存的时候都需要重写create
方法和update
方法, 如果继承的是ModelsSerializer
则不需要重写
from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
...
# 重写create方法
def create(self,valodated_data):
res = models.Punlish.objects.create(**validated_data)
return res
# 重写update方法
def update(self,instance,validated_data):
# 手动获取数据进行赋值修改
name = validated_data.get('name')
city = validated_date.get('city')
email = validated_data.get('email')
instance.name = name
instance.city = city
instance.email = email
instance.save()
return instance
.save()
class PublishView(APIView):
...
# 新增数据
def post(self,request):
publish_ser = serializer.PublishSerializer(data=request.data)
if publish_ser.is_valid():
# 直接调用 .save() 保存
publish_ser.save()
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
class PublishDetailView(APIView):
...
# 修改数据
def put(self,request,id):
publish = models.Publish.objects.filter(pk=id).first()
# 传入前端要修改的对象及传过来的数据
publish_ser = serializer.PublishSerializer(instance=publish,data=request.data)
# 得到反序列化的对象进行校验
if publish_ser.is_valid():
publish_ser.save()
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
输出的错误信息(
errors
)是英文, 要想让错误显示的是中文自定义的话, 方法与 forms 组件的方法是一样的 : 再模型类字段中添加error_massages
参数来指定
class PublishSerializer(serializers.Serializer):
...
# 重写save
def save(self, **kwargs): # kwargs是校验过后的数据
# 在父类的save内部, 调用了create, 所以我们重写create,将数据传入
res=models.Publish.objects.create(**kwargs)
return res
class PublishView(APIView):
...
# 新增数据
def post(self,request):
publish_ser = serializer.PublishSerializer(data=request.data)
if publish_ser.is_valid():
# 重写save需要手动传参
res = publish_ser.save(**publish_ser.validated_data)
publish_ser.instance = res
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
is_valid()
方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception = True
参数开启,REST框架接收到此异常,会向前端返回HTTP 400错误的请求响应publish_ser.is_valid(raise_exception=True)
# 在书写序列化类字段时加入参数来控制校验条件
class PublishSerializer(serializers.Serializer):
nid = serializers.IntegerField(required=False) # 必填
name = serializers.CharField(min_length=3) # 最短长度为3
city = serializers.CharField(max_length=16) # 最长为16
email = serializers.EmailField()
validate_[字段名]
# 校验名字不能以"xxx"开头
def validate_name(self, data):
# data就是当前字段的值
if data.startswith('xxx'):
raise ValidationError('不能以"xxx"开头')
else:
return data # 返回校验后的值
validate
# 校验名字不能与所在城市同名
def validate(self, attrs):
name = attrs.get('name')
city = attrs.get('city')
if name == city:
raise ValidationError('名字不能和城市名一样!')
else:
return attrs # 返回所有数据
# 定义一个校验函数
def name_start(data):
if data.startswith('xxx'):
raise ValidationError('不能以"xxx"开头')
else:
return data
# 然后在需要进行该校验的字段中加入 validators 参数指定该校验函数
author = serializers.CharField(validators=[name_start])
...
city = serializers.CharField(validators=[name_start])
...
re_path('^books/(?P\d+)' , views.Book2View.as_view()),
class Book2(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=16)
price = models.IntegerField()
author = models.CharField(max_length=16, null=True)
publish = models.CharField(max_length=16, null=True)
from rest_framework import serializers
class BookSerializer2(serializers.Serializer):
name = serializers.CharField(max_length=16)
price = serializers.IntegerField()
# read_only=True:该字段只用于序列化输出,只能看不能修改
author = serializers.CharField(max_length=16, read_only=True)
# write_only=True:该字段只用于反序列化输入,只能改不能查看
publish = serializers.CharField(max_length=19, write_only=True)
def update(self, instance, validated_data):
instance.title = validated_data.get('name')
instance.price = validated_data.get('price')
instance.author = validated_data.get('author')
instance.publish = validated_data.get('publish')
instance.save()
return instance
from mydrf.serializers import BookSerializer2
from mydrf import models
from rest_framework.views import APIView
from rest_framework.response import Response
class Book2View(APIView):
def get(self, request, id):
book_obj = models.Book2.objects.filter(nid=id).first()
book_ser = BookSerializer2(book_obj)
return Response(book_ser.data)
def put(self, request, id):
book_obj = models.Book2.objects.filter(nid=id).first()
book_ser = BookSerializer2(instance=book_obj, data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response(book_ser.errors)
from django.db import models
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField()
publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
class AuthorDatail(models.Model):
nid = models.AutoField(primary_key=True)
telephone = models.BigIntegerField()
birthday = models.DateField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32, null=True)
email = models.EmailField()
def __str__(self):
return self.name
from app01 import models
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
class PublishSerializer(serializers.Serializer):
nid = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=16)
city = serializers.CharField(max_length=32,error_messages={
"max_length": "太长"})
email = serializers.EmailField()
# 重写create
def create(self, validated_data):
res = models.Publish.objects.create(**validated_data)
return res
# 重写update
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.city = validated_data.get('city')
instance.email = validated_data.get('email')
instance.save()
return instance
# 局部钩子,校验出版社名字
def validate_name(self, data):
if "小黄书" in data:
raise ValidationError(f'存在敏感字符{data}')
else:
return data
# 全局钩子
def validate(self, attrs):
name = attrs.get('name')
city = attrs.get('city')
if name == '小黑出版社' and city == "上海":
raise ValidationError('该出版社已被列入黑名单')
return attrs
from app01.serializers import PublishSerializer
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
class PublishView(APIView):
# 获取所有书
def get(self, request):
publish_qs = models.Publish.objects.all()
publish_ser = PublishSerializer(instance=publish_qs, many=True) # 有多条数据的时候一定要添加
return Response(publish_ser.data)
# 新增数据
def post(self, request):
publish_ser = PublishSerializer(data=request.data)
if publish_ser.is_valid():
publish_ser.save()
return Response(publish_ser.data)
else:
# publish_ser.errors
return Response("error")
class PublishView2(APIView):
# 获取一条
def get(self, request, id):
publish_obj = models.Publish.objects.filter(pk=id).first()
publish_ser = PublishSerializer(instance=publish_obj)
return Response(publish_ser.data)
# 修改数据
def put(self, request, id):
publish_obj = models.Publish.objects.filter(pk=id).first()
publish_ser = PublishSerializer(instance=publish_obj, data=request.data)
if publish_ser.is_valid():
publish_ser.save()
return Response(publish_ser.data)
else:
return Response(publish_ser.errors)
# 删除数据
def delete(self, request, id):
# 直接删除数据,拿到影响条数的一个列表
rows = models.Publish.objects.filter(pk=id).delete()
# 取出来判断一下
if rows[0] > 0:
return Response('数据删除成功!')
else:
return Response('数据不存在!')
path('publish/', views.PublishView.as_view()),
path('publish/' , views.PublishView2.as_view()),
用来指定序列化的字段(数据表中的字段),一般使用在一个字段情况,可以跨表,可以执行方法并执行
# 更改字段名
"[另取的名字]" = serializers.CharField(source='publish') # 指定需要序列化的字段是publish
# 跨表
publish = serializers.CharField(source='publish.city')
# 执行方法,指定一个定义在模型类内方法的内存地址,会自动加括号执行
pub_date = serializers.CharField(source='times')
一般用于跨表查询, 在序列化器内部写一个get_[外键名]
,会显示指定的数据(就是显示多张表的结果)
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()
# 取出该书的出版社
publish = serializers.SerializerMethodField()
def get_publish(self, obj):
return {
'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}
# 取出该书的所有作者
authors = serializers.SerializerMethodField()
## for循环出所有作者
# def get_authors(self, obj):
# li = []
# for author in obj.authors.all():
# li.append({'id':author.nid,'name':author.name,'age':author.age})
# return li
# 列表生成式书写
def get_authors(self, obj):
return [{
'id': author.nid, 'name': author.name, 'age': author.age} for author in obj.authors.all()]
from mydrf.serializers import BookSerializer
class BookView(APIView):
def get(self, request):
book_qs = models.Book.objects.all()
book_ser = BookSerializer(instance=book_qs, many=True)
return Response(book_ser.data)
path('books/', views.BookView.as_view()),
该方法可以自定义输出的内容, 比如对一些数据进行处理后返回前端(身份证中间部分加"*****
")
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField()
publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
# 取出该书的出版社
def get_publish(self):
return {
'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}
# 取出该数的所有作者
def get_author(self):
return [{
'id': author.nid, 'name': author.name, 'age': author.age} for author in self.authors.all()]
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()
# 获取出版社和作者
publish = serializers.DictField(source="get_publish")
authors = serializers.ListField(source="get_author")
上面我们使用的 Serializer
序列化类它不是只能为数据库模型类定义, 也可以为非数据库模型类的数据定义 (也就是自己定义的数据进行序列化 : {“name”:“shawn”,“age”:18}),
serializer
是独立于数据库之外的存在, 需要自己在序列化类中去指定模型类的字段
而如果我们想要使用序列化器对应的是Django的模型类, DRF为我们提供了ModelSerializer
模型类序列化器来帮助我们快速创建一个Serializer类
create( )
和update( )
的实现, 不再需要重写这两种方法model
:指明参照哪个模型类fields
:指明为模型类的哪些字段生成class AuthorDatailSerializer(serializers.ModelSerializer):
class Meta:
model = models.AuthorDatail
fields = '__all__'
exclude
: 可以排除某这些字段, 不能与 fields
同时存在class AuthorDatailSerializer(serializers.ModelSerializer):
class Meta:
model = models.AuthorDatail
exclude = ('phone',)
depth
: 显示的深度一本书有作者, 作者有作者信息, 定义该参数会一层层显示, 层数自己控制(了解)read_only_field
: 指明只读字段, 仅用于序列化输出的字段 (弃用,有更好的方法)wirte_only_field
: 指明只写字段, 仅用于反序列化输入的字段 (弃用)class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
exclude = ('age',)
depth = 3
read_only_fields = ('nid', 'price')
...
extra_kwargs
: 使用该参数为ModelSerializer添加或修改原有的选项参数 (重点, 更好的方法)class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
extra_kwargs = {
'price': {
'min_value': 0, 'required': True},
'publish': {
'required': True, 'read_only_fields' : True},
}
模型表还是上面创建的模型表, 只是新增了点东西
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE)
# 获取用户的详情
def get_detail(self):
return {
"telephone":self.author_datail.telephone,"addr":self.author_datail.addr,"birthday":self.author_datail.birthday}
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = ['nid', 'name', 'age', 'detail', 'author_datail']
# 获取用户信息数据
detail = serializers.DictField(source="get_detail", read_only=True)
class AuthorDatailSerializer(serializers.ModelSerializer):
class Meta:
model = models.AuthorDatail
fields = '__all__'
from mydrf.serializers import AuthorSerializer
from mydrf.serializers import AuthorDatailSerializer
class AuthorView(APIView):
def get(self, request):
author_qs = models.Author.objects.all()
author_ser = AuthorSerializer(instance=author_qs, many=True)
return Response(author_ser.data)
def post(self, request):
# 将用户详情数据取出来
author_detail = request.data.pop('detail')
# 将剩余的用户数据赋值
author_dict = request.data
# 先将用户详情进行序列化操作并保存
author_detail_ser = AuthorDatailSerializer(data=author_detail)
if author_detail_ser.is_valid():
author_detail_ser.save()
# 取出用户详情数据的"nid',并将其添加到用户表的"author_datail"字段
author_detail_nid = author_detail_ser.data.get("nid")
author_dict["author_datail"] = author_detail_nid
# 再将用户信息数据进行序列化并保存
author_ser = AuthorSerializer(data=author_dict)
if author_ser.is_valid():
author_ser.save()
return Response(author_ser.data)
else:
return Response(author_ser.errors)
else:
return Response(author_detail_ser.errors)
path('author/', views.AuthorView.as_view()),
两张表都新增了数据
__new__
方法1 序列化类实例化的时候,传了many,序列化多条,不传,就序列化单条
#many=True,实例化得到的对象是ListSerializer
ser=serializer.BookModelSerializer(instance=qs,many=True)
print(type(ser)) #rest_framework.serializers.ListSerializer
# 列表中套了很多BookModelSerializer
#many=False,实例化得到的对象是BookModelSerializer
ser=serializer.BookModelSerializer(instance=book)
print(type(ser)) #app01.serializer.BookModelSerializer
类实例化:在执行__init__之前,先执行了__new__生成一个空对象(决定了是哪个类的对象)
在__new__中进行判断,如果many=True,就返回ListSerializer的对象
列表中套了很多BookModelSerializer
is_valid()
首先判断_validated_data
如果没有,执行了 self.run_validation(self.initial_data)
注意:目前在BaseSerializer,如果按住ctrl点击,会直接进到它父类的run_validation,进到Field,不是真正执行的方法
我们需要从头找,实际上是Serializer类的run_validation
def run_validation(self, data=empty):
value = self.to_internal_value(data)#字段自己的校验和局部钩子
try:
self.run_validators(value)
value = self.validate(value) # 全局钩子
assert value is not None,
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
局部钩子是在 to_internal_value执行的
def to_internal_value(self, data):
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
if validate_method is not None:
validated_value = validate_method(validated_value)
从头开始找,在自己写的serializer
里面找到Serializer
局部钩子:
to_internal_value
执行的全局钩子:
is_valid---》BaseSerializer的is_valid--》执行了self.run_validation(self.initial_data)---》Serializer的run_validation---》self.to_internal_value(data):局部钩子 或者
value = self.validate(value) :全局钩子
self.to_internal_value(data):局部钩子----》getattr(self, 'validate_' + field.field_name, None)
入口:序列化对象.data方法
流程分析:
图解:
如果你在序列化器中想重写某个字段 (比如为Book的作者名都加上"xxx"后缀)
# models.py 文件中在模型类中书写方法
def join_xxx(self,obj):
return obj.name + "xxx"
# serializers.py 文件中对应的Book序列化类中重写字段指定方法
authors = serializer.CharField(source='join_xxx')
# serializers.py 文件中的Book序列化器书写
authors = serializers.SerializerMethodField()
def join_xxx(self,obj):
return obj.name + "xxx"
many=False
, 多个数据需填写 many=True
# serializers.py 文件中创建子序列化类,并将子序列化类加入序列化类中
# 子序列化类必须写在上方
class AuthorSerializer(serializer.ModelSerializer):
class Meta:
model = models.Author
fields = ["name"]
class BookSerializer(serializer.ModelSerializer):
# 书写子序列化字段
authors = AuthorSerializer(many=True, read_only=True)
class Meta:
model = models.Book
fields = ["name","price","publish","authors"]