第二章 restframework——框架安装与APIView
一、restframework框架安装
二、Django的CBV源码分析
三、APIView介绍
四、django中的request
五、restframework中的request
一、restframework框架安装
方式一:pip3 install djangorestframework
方式二:pycharm图形化界面安装
方式三:pycharm命令行下安装(装在当前工程所用的解释器下)
切记去项目settings.py配置中配置restframework
否则会报如下错误
二、Django的CBV源码分析
CBV(class base view):基于类的view,就叫CBV
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
使用步骤:
①使用前切记导入View,将创建的类继承自View
from django.views import View
②该类会自动根据post请求与get请求自动分辨请求类型,选择对应的函数def get()或者def post()
③dispatch类似装饰器,可以在def get()或者def post()前后添加代码
记得继承类obj=super().dispatch(request, *args, **kwargs),在其前后添加代码
④在路由调用视图函数时记得调用as_view()方法
from django.views import View
class AddPublish(View):
def dispatch(self, request, *args, **kwargs):
print(request)
print(args)
print(kwargs)
# 可以写类似装饰器的东西,在前后加代码
obj=super().dispatch(request, *args, **kwargs)
return obj
def get(self,request):
return render(request,'index.html')
def post(self,request):
request
return HttpResponse('post')
源码分析(右击新标签中打开图片可以看的清楚些)
使用装饰器装饰CBV(dispatch)
类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。
Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
# 使用CBV时要注意,请求过来后会先执行dispatch()这个方法,如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,
这个dispatch方法就和在FBV上加装饰器的效果一样。
class Login(View):
def dispatch(self, request, *args, **kwargs):
print('before')
obj = super(Login,self).dispatch(request, *args, **kwargs)
print('after')
return obj
def get(self,request):
return render(request,'login.html')
def post(self,request):
print(request.POST.get('user'))
return HttpResponse('Login.post')
三、APIView介绍
使用步骤:
①导入模块
from rest_framework.views import APIView
②使CBV继承自restframework中的APIView而非django的View
上文分析了django中的as_view方法,让我们看看APIView中的as_view()
@classmethod def as_view(cls, **initkwargs): """ Store the original class on the view function. This allows us to discover information about the view when we do URL reverse lookups. Used for breadcrumb generation. """ if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
实际执行的还是djangoView类中的as_view()方法下的view函数
view()执行什么实际就是dispatch执行什么
然而restframework也重写了dispatch方法(只截取部分)(切记下面的dispatch方法是restframework的,并且该框架核心就在此)
【重要】
总结:
views.PublishView.as_view()的执行意味着父类View类型下的as_view()方法下的view(request)的执行,
由于restframework中dispatch已经重写,view(request)的执行意味着APIView类下的dispatch的执行。
可能表述不太清晰,具体看下面的流程
路由as_view()——》【django】View().as_view().view()——》【restframework】dispatch()
四、django中的request
在了解django中的request之前先来回顾下http协议的请求数据结构
如下图get请求中的数据在请求头的url中,而post请求则在请求体内
下面演示使用Postman
1.get请求
①模拟发起带参数的get请求
②页面返回ok
③request.GET返回QueryDict对象
2.django中的POST请求略有不同
①模拟发起带参数的post请求(模拟urlencoded发送)
②页面返回post
③request.POST返回QueryDict对象,body返回body体内容
④注意:django的request内的post请求有一个特殊之处,当请求采用json格式时,request.POST没有数据
源码解析:
django源码中会有类似如下判断
# 伪代码
if contentType:urlencoded: a=1&b=2----->{"a":1,"b":2}
A)通过type查找request的类型
print(type(request))
B)导入WSGIRequest
from django.core.handlers.wsgi import WSGIRequest
C)点击进入
D)查看_get_post
E)查看_load_post_and_files(),印证了上面的猜测
五、restframework中的request
第三节中分析了restframework中的as_view()实际执行的是restframework自己写的dispatch,那让我们看一下
initialize_request()
为了更深入研究,我们看下这个Request类
也就是说,现在cbv里面的request已经是新的request了,他经过一系列封装,增加了例如解析json格式数据的功能等等
所以,原生的request方法将不再适用,新的request将拥有新的方法
①操作django的request的方法
②request.data
【post请求】
发送json数据
注意:
①django将request的所有方法的数据获取进行了不同的封装,而restframework将request下POST方法(application/json形式)的数据封装成request.data
②restframework内的request.POST只能接收urlencoded形式发送的数据
收到的就是dict类型
发送urlencoded数据
收到的依旧是querydict类型
【get请求】
我们可以尝试request.data能否也取到值(答案是不行),可以证明data对post请求有效
那再试试操作django的request下的方法
上面这样写太麻烦了,restframework为我们做了处理
也可以用request.query_params来取