在学习django restful framework之前我们要先回顾一下:
1. 开发模式
- 普通开发方式(之前我们在开发的时候前后端放在一起写,也就是说一个人会负责前端和后端的代码,这样就会导致开发的效率较低,而且如果后端开发人员的前端基础较差的话,就会导致产品的质量不是很好)
- 前后端分离(前端人员做前端,VUE,后端的人员写后端的代码,因为很多的时候通过vue都是通过json数据进行传输的,因此作为后端的人员只需要将自己的数据通过json序列化之后就可以了)
2. 后端开发
为前端提供URL(API/接口的开发)
注:永远返回HttpResponse(通过json的形式)
3. Django FBV、CBV
FBV,function base view
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
CBV,class base view
路由:
url(r'^students/', views.StudentsView.as_view()),
视图:
from django.views import View
class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
ps:学会使用postman来模拟post请求
4. 列表生成式
class Foo:
pass
class Bar:
pass
v = []
for i in [Foo,Bar]:# 循环每个类
obj = i()# 类加括号实例化
v.append(obj)# 因此v里面就会有两个类的实例化对象
v = [item() for item in [Foo,Bar]] # 列表生成式
v其实就是一个对象列表
5. 面向对象基础知识
- 封装
- 对同一类方法封装到类中
class File:
文件增删改查方法
Class DB:
数据库的方法
- 将数据封装到对象中
class File:
def __init__(self,a1,a2):
self.a1 = a1
self.xxx = a2
def get:...
def delete:...
def update:...
def add:...
obj1 = File(123,666)
obj2 = File(456,999)
PS: 扩展
class Request(object):
def __init__(self,obj):
self.obj = obj
@property
def user(self):
return self.obj.authticate()
class Auth(object):
def __init__(self,name,age):
self.name = name
self.age = age
def authticate(self):
return self.name
class APIView(object):
def dispatch(self):
self.f2()
def f2(self):
a = Auth('alex',18)
b = Auth('oldboy',18)
req = Request(b)
print(req.user)
obj = APIView()
obj.dispatch()
6.CVB形式的源码分析
1.因为每个url对应的都是一个函数,也就是一个视图当代码运行到url(r'^students/', views.StudentsView.as_view())这里的时候其实就是返回一个视图,通过as_view->view返回一个视图函数
2.def as_view(cls, **initkwargs)-->def view(request, *args, **kwargs);当执行self = cls(**initkwargs)这句话的时候,cls加括号也就是实例化这个类,等价于:self = StudentsView()
3.下面就会执行return self.dispatch(request, *args, **kwargs)中的dispatch方法;换个方式:ret = self.dispatch(request, *args, **kwargs),return ret 也就是执行StudentsView里面的dispatch方法;执行dispatch是有返回值的,返回的值就是Httpresponse以及render,redreit等等;换句话说也就是请求进来之后直接执行dispatch,无论是什么请求进来都会执行dispatch
def dispatch(self, request, *args, **kwargs):
func = getattr(self, request.method.lower()) #通过反射拿到请求方式然后转成小写
ret = func(request, *args, **kwargs)# 执行函数
return ret
4.在源码中如何实现的呢?
def dispatch(self, 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
return handler(request, *args, **kwargs)
FBV、CBV笔记说明:
CBV,基于反射实现根据请求方式不同,执行不同的方法。
原理:
url -> view方法 -> dispatch方法(反射执行其他:GET/POST/DELETE/PUT)
如果这样写呢?执行父类的方法
流程:
class StudentsView(View):
def dispatch(self, request, *args, **kwargs):
print('before')
ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
print('after')
return ret
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
流程:
1.请求一进来先执行dispatch方法,然后执行父类的dispatch方法
2.里面的self指的是StudentsView,然后父类里面的handler = getattr(self, request.method.lower(), self.http_method_not_allowed)的self也是StudentsView,最后返回Httpresponse对象,然后将ret返回
继承:
1 继承(多个类共用的功能,为了避免重复编写):
2 from django.views import View
3
4
5 class MyBaseView(object):
6 def dispatch(self, request, *args, **kwargs):
7 print('before')
8 ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)
9 print('after')
10 return ret
11
12 class StudentsView(MyBaseView,View):
13
14 def get(self,request,*args,**kwargs):
15 print('get方法')
16 return HttpResponse('GET')
17
18 def post(self, request, *args, **kwargs):
19 return HttpResponse('POST')
20
21 def put(self, request, *args, **kwargs):
22 return HttpResponse('PUT')
23
24 def delete(self, request, *args, **kwargs):
25 return HttpResponse('DELETE')
26
27 class TeachersView(MyBaseView,View):
28
29 def get(self,request,*args,**kwargs):
30 return HttpResponse('GET')
31
32 def post(self, request, *args, **kwargs):
33 return HttpResponse('POST')
34
35 def put(self, request, *args, **kwargs):
36 return HttpResponse('PUT')
37
38 def delete(self, request, *args, **kwargs):
39 return HttpResponse('DELETE')
7.csrf补充
7.1. django中间件
- process_request
- process_view
- process_response
- process_exception
- process_render_template
当请求到来的时候,先是执行process_request,然后再执行process_view,再进入视图函数
7.2. 使用中间件做过什么?
- 权限
- 用户登录验证
- django的csrf是如何实现?
是放在process_view方法里面的:
如果加上from django.views.decorators.csrf import csrf_exempt,csrf_exempt免除csrf验证
- 检查视图是否被 @csrf_exempt (免除csrf认证)
- 去请求体或cookie中获取token
7.3:FBV
情况一:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # 全站使用csrf认证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt # 该函数无需认证
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
情况二:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', # 全站不使用csrf认证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
from django.views.decorators.csrf import csrf_exempt
@csrf_protect # 该函数需认证
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
7.4:CBV
CBV小知识,csrf时需要使用
- @method_decorator(csrf_exempt)
- 在dispatch方法中(单独方法无效)
方式一:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
class StudentsView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(StudentsView,self).dispatch(request, *args, **kwargs)
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
方式二:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name='dispatch')
class StudentsView(View):
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
8.restful 规范(建议)
a. 接口开发
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^get_order/', views.get_order),
url(r'^add_order/', views.add_order),
url(r'^del_order/', views.del_order),
url(r'^update_order/', views.update_order),
]
def get_order(request):
return HttpResponse('')
def add_order(request):
return HttpResponse('')
def del_order(request):
return HttpResponse('')
def update_order(request):
return HttpResponse('')
这样就会出现一个小问题,url会越来越多,不好维护
b. restful 规范(建议)
1. 根据method不同做不同的操作,示例:
基于FBV:
urlpatterns = [
url(r'^order/', views.order),
]
def order(request):
if request.method == 'GET':
return HttpResponse('获取订单')
elif request.method == 'POST':
return HttpResponse('创建订单')
elif request.method == 'PUT':
return HttpResponse('更新订单')
elif request.method == 'DELETE':
return HttpResponse('删除订单')
基于CBV:
urlpatterns = [
url(r'^order/', views.OrderView.as_view()),
]
class OrderView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('获取订单')
def post(self,request,*args,**kwargs):
return HttpResponse('创建订单')
def put(self,request,*args,**kwargs):
return HttpResponse('更新订单')
def delete(self,request,*args,**kwargs):
return HttpResponse('删除订单')
get:获取;delete:删除;post:创建;put:更新
9.安装:django rest framework框架
源码分析:cbv
1.当请求进来的时候首先会通过url对应一个函数,对于cbv的方式先会调用按时as_view,再去调用view方法返回对应的视图函数,最重要的是里面的dispatch方法
2.
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
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),在initialize_request这个方法中封装了一个Request
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
这里面的request是原生的request,里面的authenticators返回的是一个对象列表:接下来我们进入get_authenticators()这个方法中去:return [auth() for auth in self.authentication_classes],返回的是一个列表生成式,也就是认证类的对象
因此执行了request = self.initialize_request(request, *args, **kwargs)这句话之后,那么这个request是一个全新的request,丰富了原生的request的内容
接下来就会执行self.initial(request, *args, **kwargs)这个方法,再去执行self.perform_authentication(request)这个方法,将新的request放入这个方法去处理:返回的是request.user
我们再看user里面是做了些什么:
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
通过for authenticator in self.authenticators:这个循环取到认证类的对象,然后一个个的认证,最后返回一个request.user
代码示例:
1 - 仅使用:
2 from django.views import View
3 from rest_framework.views import APIView
4 from rest_framework.authentication import BasicAuthentication
5 from rest_framework import exceptions
6 from rest_framework.request import Request
7
8 class MyAuthentication(object):
9 def authenticate(self,request):
10 token = request._request.GET.get('token')
11 # 获取用户名和密码,去数据校验
12 if not token:
13 raise exceptions.AuthenticationFailed('用户认证失败')
14 return ("alex",None)
15
16 def authenticate_header(self,val):
17 pass
18
19 class DogView(APIView):
20 authentication_classes = [MyAuthentication,]
21
22 def get(self,request,*args,**kwargs):
23 print(request)
24 print(request.user)
25 ret = {
26 'code':1000,
27 'msg':'xxx'
28 }
29 return HttpResponse(json.dumps(ret),status=201)
30
31 def post(self,request,*args,**kwargs):
32 return HttpResponse('创建Dog')
33
34 def put(self,request,*args,**kwargs):
35 return HttpResponse('更新Dog')
36
37 def delete(self,request,*args,**kwargs):
38 return HttpResponse('删除Dog')