文章目录
昨日回顾
1 restful规范
只是一个规范,规范了前后端交互接口(api接口)格式
10条规范
- http部署
- 请求地址中有接口标识
-https://api.baidu.com
-https://www.baidu.com/api/
- 多版本共存
-https://www.baidu.com/api/v1
-https://www.baidu.com/api/v2
- 请求资源名词表示,可以复数
-一切皆资源
-https://www.baidu.com/api/v1/books/
- 请求方式表示操作资源的方式
-get:获取资源
-post:新增资源
-put:修改
-patch:修改
-delete:删除资源
-响应中带状态码
-{code:100}
-响应中带错误信息
-{code:100,msg:'错误'}
-响应中带链接地址
-响应数据遵循以下格式
-多条数据 []
-单条 {}
-新增 新增的数据返回
-修改 修改的数据返回
-删除 空文档
-请求中带过滤条件
2 序列化器
-把对象----》序列化器---》字典-----》Response--->json格式字符串给前端
-把前端传过来的数据---Request-》字典---》序列化器----》对象---》保存
-数据校验
-如何使用
-写一个序列化类 继承Serializer
-在类中写字段
-字段类型:CharField...
-字段属性参数:required...
-在视图类中使用
-实例化得到对象
-序列化(对象--》字典)ser=XXSerialier(instance=对象,many=True)----》ser.data
-反序列化(新增)(字典---》对象)ser=XXSerialier(data=字典)
-反序列化的校验(三种方式)
-字段自己的校验
-validators=[函数内存地址,]
-局部和全局钩子
-validate_字段名(self,data)
-validate(self,attrs)
-wirte_only和read_only
今日内容
1 修改,删除接口
views.py
def put(self, request, id):
# 通过id取到对象
res = {'code': 100, 'msg': ''}
try:
book = models.Book.objects.get(id=id)
ser = BookSerializer(instance=book, data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
res['msg'] = '修改成功'
res['result'] = ser.data
except Exception as e:
res['code'] = 101
res['msg'] = str(e)
return Response(res)
def delete(self,request,id):
response = {'code': 100, 'msg': '删除成功'}
models.Book.objects.filter(id=id).delete()
return Response(response)
serializer.py
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
title = serializers.CharField(max_length=32,min_length=2)
price = serializers.DecimalField(max_digits=5, decimal_places=2)
publish = serializers.CharField(max_length=32)
def create(self, validated_data):
res=models.Book.objects.create(**validated_data)
print(res)
return res
def update(self, book, validated_data):
book.title=validated_data.get('title')
book.price=validated_data.get('price')
book.publish=validated_data.get('publish')
book.save()
return book
2 高级用法之source
2.1 修改返回到前端的字段名
source=title(title对应models里的title字段) ,在这里重新命名为name,这样返回到前端的字段名就为name
注意:返回到前端字段名就不能再叫title了,这里是name
name = serializers.CharField(max_length=32,min_length=2,source='title')
2.2 如果表模型中有方法
# 执行表模型中的test方法,并且把返回值赋值给xxx
xxx=serializers.CharField(source='test')
models.py
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32,null=True)
price = models.DecimalField(max_digits=5, decimal_places=2,null=True)
# publish = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)
def test(self):
# python是强类型语言,不支持字符串和数字直接相加
return self.title+str(self.price)
class Publish(models.Model):
name=models.CharField(max_length=32)
addr=models.CharField(max_length=32)
def __str__(self):
return self.name
2.3 source支持跨表操作
addr=serializers.CharField(source='publish.addr')
# 希望你们去看以下源码,内部如何实现的
3 模型类序列化器
原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系
ModelSerializer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
3.1 定义
比如我们创建一个BookModelSerializer类
class BookModelSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = '__all__'
-
model 指明参照哪个模型类
-
fields 指明为模型类的哪些字段生成
-
fields=[字段,字段] : 序列化的字段,反序列化的字段
-
fields=‘all’ 所有字段都序列化,反序列化
-
exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用)
-
read_only_fields=[‘price’,‘publish’] --序列化显示的字段
-
write_only_fields=[‘title’] – 反序列化需要传入的字段
-
extra_kwargs ={‘title’:{‘max_length’:32,‘write_only’:True}}
-
depth=1 – 了解,跨表1查询,最多建议写3
3.2 指定字段
- 使用fields来明确字段,
__all__
表名包含所有字段,也可以写明具体哪些字段,如
class BookModelSerializer(serializers.ModelSerializer):
publish=serializers.CharField(max_length=32,source='publish.name')
addr=serializers.CharField(max_length=32,source='publish.addr')
class Meta:
model=models.Book # 该序列化类跟Book表建立了关系
fields=['id','title','publish','addr'] # 序列化book表中的id,title,publish和addr字段
# fields='__all__'
- 使用exclude可以明确排除掉哪些字段
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=models.Book # 该序列化类跟Book表建立了关系
exclude=['publish']
- 显示指明字段,如:
class BookModelSerializer(serializers.ModelSerializer):
# 重写某些字段
publish=serializers.CharField(max_length=32,source='publish.name')
addr=serializers.CharField(max_length=32,source='publish.addr')
class Meta:
model=models.Book # 该序列化类跟Book表建立了关系
fields=['id','title','publish','addr'] # 序列化book表中的id,title,publish和addr字段
- 指明只读字段
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=models.Book # 该序列化类跟Book表建立了关系
fields=['id','title','price','publish']
read_only_fields=['price'] # 序列化显示的字段
write_only_fields=['title']# 反序列化需要传入的字段
3.3 添加额外参数选项
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
extra_kwargs ={'title':{'max_length':32},'price':{'validators':[check,]}}
extra_kwargs ={'title':{'max_length':32,'write_only':True}}
注意:
新增,时改是统统不用重写create和update方法了,在ModelSerializer中重写了create和update
局部钩子,全局钩子,跟原来完全一样
了解:
class BookModelSerializer(serializers.ModelSerializer):
# publish = serializers.CharField(max_length=32, source='publish.name')
class Meta:
model = models.Book
fields = '__all__'
# depth=1 # 跨表1查询,个人建议最多不要超过3,尽量不要用
4 高级用法之SerializerMethodField
例:取出图书的出版社详细信息(id,name,addr)
#方法一
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=32,min_length=2,source='title')
price = serializers.DecimalField(max_digits=5, decimal_places=2)
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
dic={'name':obj.publish.name,'addr':obj.publish.addr, 'id': obj.publish.id}
return dic
#方法二
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
dic={'name':obj.publish.name,'addr':obj.publish.addr}
return dic
## #方法三,使用序列化类的嵌套
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
# fields = '__all__'
fields = ['name','addr']
class BookModelSerializer(serializers.ModelSerializer):
publish = PublishSerializer()
class Meta:
model = models.Book
fields = '__all__'
5 drf的请求与相应
# Request
-data :前端以post请求提交的数据都在它中
-FILES :前端提交的文件
-query_params:就是原来的request.GET
-重写了 __getattr__
-使用新的request.method其实取得就是原生request.method(通过反射实现)
# Response
-from rest_framework.response import Response
-data:响应的字典
-status:http响应的状态码
-drf提供给你了所有的状态码,以及它的意思
from rest_framework.status import HTTP_201_CREATED
-template_name:模板名字(一般不动),了解
-headers:响应头,字典
-content_type:响应的编码方式,了解
6 自己封装一个Response对象
views.py
from app01.utils import CommonResponde
from rest_framework.status import HTTP_201_CREATED
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookDetail(APIView):
# renderer_classes = [BrowsableAPIRenderer, ]
def get(self,request,id):
res=models.Book.objects.all().filter(id=id).first()
ser=BookSerializer(instance=res)
return Response(ser.data)
def put(self,request,id):
res=CommonResponde()
try:
book=models.Book.objects.get(id=id)
ser=BookModelSerializer(instance=book,data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
res.msg='成功'
res.code = 100
res.result=['dfghjkll']
except Exception as e:
print(str(e))
res.msg='未知错误'
res.code=101
return Response(data=res.get_dic,status=HTTP_201_CREATED)
serializer.py
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model=models.Publish
fields=['name','addr']
class BookModelSerializer(serializers.ModelSerializer):
# publish=PublishSerializer()
class Meta:
model=models.Book
fields='__all__'
utils.py
class CommonResponde:
def __init__(self):
self.code=100
self.msg=''
@property
def get_dic(self):
return self.__dict__
# 自己封装一个response,继承drf的Response
7 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
-配置文件方式(全局)
-如果没有配置,默认有浏览器和json
-drf有默认配置文件
from rest_framework.settings import DEFAULTS
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # json渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
)
}
-在视图类中配置(局部)
-粒度更小
-class BookDetail(APIView):
renderer_classes=[JSONRenderer,]
8 many=True源码分析,局部全局钩子源码解析
1 many=True
-__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁
2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)
-Serializer这个类的:self.run_validation
def run_validation(self, data=empty):
value = self.to_internal_value(data) # 局部字段自己的校验和局部钩子校验
try:
self.run_validators(value)
value = self.validate(value) # 全局钩子的校验
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value