APIView
- drf: 第三方的app,只能在django上使用(不同版本对django的版本有所要求)
- drf安装后,导入一个视图类APIView
- 使用drf写视图类要继承APIView及其子类
基本使用
使用View+JsonResponse与APIView+drf对比
- View+JsonResponse
from django.views import View
from .models import Book
class BookView(View):
def get(self,request):
book_list = Book.objects.all()
res_list = []
for book in book_list:
res_list.append({'name':book.name,'price': book.price,'publish':book.publish})
return JsonResponse(res_list,safe=False,json_dumps_params={'ensure_ascii':False})`
- APIView+drf
- 不要忘了注册rest_framework这个app
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
class BookView(APIView):
def get(self,request):
book_list = Book.objects.all()
res_list = []
for book in book_list:
res_list.append({'name':book.name, 'price':book.price, 'publish':book.publish})
return Response(res_list)
源码分析
- 视图类继承APIView后,执行流程发生了变化,此变化就是整个的drf的执行流程
- 从参数得APIView入手
APIView --> as_view -->super().as_view–> self.dispatch–>dispatch
APIView --> as_view -->csrf_exempt
@csrf_exempt
def index(request):
本质等同于 index=csrf_exempt(index)
# 请求来了,路由匹配成功后执行
def dispatch(self, request, *args, **kwargs):
# 参数的request是原来的django原生的request
# 下面的request,变成了drf提供的Request类的对象---》return Request(。。。)
总结:
- 继承APIView后都没有csrf的认证了
- 以后视图类中使用的request对象,已经变成了drf提供的Request对象了
- 执行视图类的方法前,执行了三大认证(认证,权限,频率)
- 在执行三大认证和视图类的方法过程报错,直接使用异常捕获
Request类源码分析
- 视图类内的request对象已被drf内的Request对象替换
原生django的request对象是
(django.core.handlers.wsgi.WSGIRequest)类的
drf的request对象是
(rest_framework.request.Request)类的
- request虽然不是原来的当仍然可以使用
print(request.method) # get
print(request.path) # /books/
print(request.GET) # 原来的get请求提交的参数
print(request.POST) # 原来post请求提交的参数
- Request源码
# from rest_framework.request import Request rest_framework.request.Request # 类中有个魔法方法:__getattr__ 对象.属性,属性不存在会触发它的执行 def __getattr__(self, attr): # 如果取的属性不存在会去原生django的request对象中取出来 try: #反射:根据字符串获取属性或方法,self._request 是原来的request return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr)
- 新的request内部有一个老的request,是request._request
- data是方法,被property装饰后,变为了数据属性
- 以后body体中提交的数据,都从这里取(request.POST)
- 取文件也是从request.FILES中取
- query_params:get请求提交的参数,等同于request._request.GET 或 request.GET
“”"
-以后body体中提交的数据,都从这里取(request.POST)
-urlencoded,form-data:提交的数据在request.POST中
-json格式提交的数据,在requets.POST中没有,它在request.body中
-现在无论那种格式,都从request.data中取
“”"
- 魔法方法? __开头,__结尾
序列化
序列化组件
- 序列化组件时就是,drf提供的一个类,我们通过继承它,重写自己的类
- drf提供了一种可以快速实现序列化的类:序列化类
定义一个序列化类
# serializer.py
from .models import Book
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name= serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
# views.py
from django.http import JsonResponse
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import BookSerializer
class BookView(APIView):
# 序列化一条
def get(self,request):
book_list = Book.objects.all()
ser = BookSerializer(instance=book_list,many=True)
return Response(ser.data)
# 新增
def post(self,request):
print(request.data)
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(APIView):
# 序列化单条
def get(self,request,pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
# 修改
def put(self, request,pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book,data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
# 删除
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response()
# serializer.py
from .models import Book
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name= serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self,validated_data):
res = Book.objects.create(**validated_data)
return res
def update(self,instance,validated_data):
instance.name = validated_data.get('name')
instance.name = validated_data.get('price')
instance.name = validated_data.get('publish')
instance.save()
return instance
使用序列化类,序列化多条数据
使用序列化类,序列化单条数据
反序列化
使用反序列化类,新增与修改
新增
修改
2 .fbv写—》写个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用request.data,这个data无论是那种编码格式,都有数据
from django.http import JsonResponse
def out_view(func_name):
def inner(request, *args, **kwargs):
request = APIView().initialize_request(request)
res = func_name(request, *args, **kwargs)
return res
return inner
# @csrf_exempt
@ out_view
def index(request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return JsonResponse(ser.data)
else:
return JsonResponse(ser.errors)