在學習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')
