今日内容概要
- APIView执行流程
- Request对象源码分析
- 序列化器介绍和快速使用
- 反序列化
- 基于序列化器编写5个接口
- 反序列化的校验
今日内容详细
APIView执行流程
'''基于APIView+JsonResponse编写接口'''
drf提供了一个类 之后使用drf编写视图类 都是集成这个类及其子类 APIView本身就是继承了django原生的View
from rest_framework.views import APIView
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
book_list = []
for book in books:
book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return JsonResponse(book_list, safe=False)
'''基于APIView+Response编写接口'''
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
book_list = [{'name': book.name, 'price': book.price, 'publish': book.publish} for book in books]
return Response(book_list) # Response无论是列表还是字典都可以被序列化
'''APIView的执行流程'''
路由 path('api/v1/books/', views.BookView.as_view()),
当请求来了并且匹配成功--->执行views.BookView.as_view()--->自身类并没有as_view()函数 父类中有 那么执行父类的as_view() 也就是APIView中的as_view()
@classmethod
def as_view(cls, **initkwargs):
# 执行父类View中的as_view 返回的是闭包函数view的内存地址
view = super().as_view(**initkwargs)
# csrf_exempt是将csrf认证去除 原本是一个装饰器
# 相当于是将BookView中所有方法都装上了这个装饰器
return csrf_exempt(view)
执行csrf_exempt(view)也就是加了装饰器的view函数--->view函数返回的是self.dispatch此时的self是视图类的对象--->视图类并没有dispatch方法去父类APIView中找--->查看源码发现有
def dispatch(self, request, *args, **kwargs):
# 将老的request传入initialize_request方法 并将结果赋值给request 具体看图
request = self.initialize_request(request, *args, **kwargs)
self.request = request
try:
# 执行了三大认证(认证 频率 权限) 用的是新的request
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
# 视图类中使用的request也是新的
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
总结:
1.APIView去除了所有的csrf认证
2.使用了新的request 也就是Request类的对象 不再是django原生的request
3.执行视图类的方法之前都会执行3大认证
4.如果在执行视图类方法和3大认证出现了错误 会被捕获--->全局异常捕获
Request对象源码分析
from rest_framework.request import Request
查看Request源码
我们发现新的request也可以执行request.method方法 但是源码中并没有 可以联想到魔法方法__getattr__ 点不存在的名字的时候执行该方法下的代码 源码中的确有该方法
def __getattr__(self, attr):
try:
# 可以发现是利用的反射 使用老的request取得想要的属性
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
request.data---->这是个方法 被伪装成了数据属性
主要作用是 之后无论post put等等放在body中的数据都是从该方法中取到 取出来的就是字典 无论是哪种编码格式
request.query_params---->这是个方法 被伪装成了数据属性
get请求携带的数据 都从这儿取
查询参数 restful规范请求地址中带查询参数
request.FILES---->这是个方法 被伪装成了数据属性
前端提交过来的文件 从这儿取
Request类总结
1.新的request用起来和之前的一模一样 当新的某些方法取不到 就会通过__getattr__方法取旧的
2.request.data 无论什么编码 什么请求方式 只要是body中的数据 都从这里取 以字典形式
3.request.query_params 就相当于原来的request.GET--->request._request.GET
4.上传的文件从request.FILES中取
序列化器介绍和快速使用
再写接口的时候 需要序列化和反序列化 并且反序列化的过程中需要做数据的校验 drf中直接提供了固定的写法 只需要按照固定写法使用 就可以完成上面的三个需求
提供了两个类 Serializer和ModelSerializer
之后只需要写自己的类 继承drf提供的序列化类 使用其中的某些方法就行
创建一个serializer的py文件 并写一个序列化类
from rest_framework import serializers
class BookSerizlizer(serializers.Serializer):
# 编写需要序列化的字段
name = serializers.CharField() # 编写方式大致与models下的类是对应的
price = serializers.CharField()
views.py下
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
# 使用序列化类来完成
# instance需要接收要序列化的数据
# many=True 只要是queryset对象就要传 单个对象就不用传
ser = BookSerizlizer(instance=books, many=True)
return Response(ser.data) # 无论是列表还是字典都可以被序列化
# 序列化类产生的对象.data取到的是序列化后的数据
序列化单条的话类似 只需要稍微修改视图类即可 可以重新写一个视图类 或者结合在一起
def get(self, request, *args, **kwargs):
if kwargs:
book = Book.objects.filter(**kwargs).first()
ser = BookSerializers(instance=book)
return Response(ser.data)
books = Book.objects.all()
ser = BookSerializers(instance=books, many=True)
return Response(ser.data)
路由层
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/books/', views.BookView.as_view()),
path('api/v1/books/<int:pk>/', views.BookView.as_view()),
]
反序列化
'''反序列化类的新增'''
序列化类中
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
# 保存的逻辑
# validated_data 校验过后的数据 {name,price,publish}
# 保存到数据库
book = Book.objects.create(**validated_data)
# 一定要返回新增的对象
return book
视图类中
class BookView(APIView):
def post(self, request):
# requset.data # 前端提交的要保存的数据----》校验数据---》存
ser = BookSerializer(data=request.data) # 把前端传入的要保存的数据,给data参数
# 校验数据
if ser.is_valid():
# 保存---->需要自己写,要在序列化类BookSerializer中写create方法
ser.save() # 调用ser.save,自动触发自己写的create 并保存
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
return Response({'code': 101, 'msg': ser.errors})
'''反序列化类的修改'''
序列化类中
def update(self, instance, validated_data):
# instance 要修改的对象
# validated_data 校验过后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save() # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库
return instance # 不要忘了吧修改后的对象,返回
基于序列化器编写5个接口
class BookView(APIView):
def get(self, request, *args, **kwargs):
if kwargs:
book = Book.objects.filter(**kwargs).first()
ser = BookSerializers(instance=book)
return Response(ser.data)
books = Book.objects.all()
ser = BookSerializers(instance=books, many=True)
return Response(ser.data)
def post(self, request, *args, **kwargs):
ser = BookSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
return Response({'code': 101, 'msg': ser.errors})
def put(self, request, *args, **kwargs):
book = Book.objects.filter(**kwargs).first()
ser = BookSerializers(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, *args, **kwargs):
Book.objects.filter(**kwargs).delete()
return Response({'code': 102, 'msg': '删除成功'})
反序列化的校验
序列化类反序列化有数据校验功能 类似于forms组件
class BookSerializer(serializers.Serializer):
# 局部钩子
# 反序列化校验的局部钩子 ,名字不能以sb开头
def validate_name(self, name):
# 校验name是否合法
if name.startswith('sb'):
# 校验不通过,抛异常
raise ValidationError('不能以sb开头')
else:
return name
# 全局钩子
def validate(self, attrs):
# 校验过后的数据,书名跟出版社名字不能一致
if attrs.get('name') == attrs.get('publish'):
raise ValidationError('书名跟出版社名字不能一致')
else:
return attrs
标签:drf3,return,ser,self,request,序列化,data
From: https://www.cnblogs.com/lzjjjj/p/17087189.html