源碼繁瑣,多說無益,耐心細讀官方文檔:數據庫
https://www.django-rest-framework.org/django
我的總結:json
REST是一種軟件架構設計風格,不是標準,也不是具體的技術實現,只是提供了一組設計原則和約束條件。api
DRF(Django RestFramework)是一套基於Django開發的、幫助咱們更好的設計符合REST規範的Web應用的一個Django App,因此,本質上,它是一個Django App。瀏覽器
安裝: (肯定Django已經安裝)服務器
>>> pip install djangorestframework
1 APIView cookie
首先須要瞭解django中views.View類及其相關流程,看以下關係圖(最好看源碼):session
DRF APIView請求流程:架構
DRF對django視圖配置流程圖(我的畫)app
2 解析器組件 (用來解析數據的請求的組件)
Django並不能處理請求協議爲application/json編碼協議的數據
注意: DRF解析器會封裝到View中的parsers內,在視圖函數被調用時,會傳入request,經過request.data拿到數據才進行解析 ,即解析器解析是在request對象傳入後.
解析器組件流程圖:
//解析器的使用方式: //1,導入模塊 views.py from rest_framwork.views import APIView //2, 繼承APIView class BookView(APIView): def get(self, request): pass //3, url.py from django.urls import path, include, re_path from classbasedview import views urlpatterns = [ re_path('login/$', views.LoginView.as_view()), ] //4, def post(self, request): origin_data = request.data ... return HttpResponse({})
試用工具: postman---經過postman來模擬用戶請求,再也不須要使用瀏覽器來發送請求.(直接在官網下載便可)
3 序列化組件
序列化組件的使用:
--get接口設計:
{{ 實踐代碼 }}
--post接口設計
{{ 實踐代碼 }}
使數據自動插入並且更加簡單:
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('title', 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': {'write_only': True}, 'authors': {'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset開始循環 [{}, {}, {}, {}]
authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
步驟以下:
繼承ModelSerializer: 再也不繼承Serializer
添加extra_kwargs類變量: extra_kwargs = { 'publish':{'write_only':True}}
4 視圖組件
使用視圖組件進行接口邏輯化
導入mixin
from rest_framework.mixinx import ( ListModelMix, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin ) from rest_framework.generics import GenericAPIView
定義序列化類
Class BookSerializer(serializers.ModelSerializer): class Meta: Book fields = () extra_kwargs = {"field_name": {"write_only": True}}
導入序列化類
from .app_serializers import BookSerializer
定義視圖類
class BookView(ListModelMix, CreateModelMixin, GenericAPIView): # queryset和serializer_class是固定的寫法
queryset = Book.objects.all() serializer_class = BookSerializer def get(): return self.list() def post(): return self.create() class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(): return self.retrieve() def delete(): return self.destroy() def put(): return self.update()
注意: 單條數據操做的url是這樣的:re_path(r'books/(?P<pk>\d+)/$, views.BookFilterView.as_view())
使用視圖組件的view進行接口邏輯優化
導入模塊 from rest_framework import generics
寫試圖類
class BookView(generics.ListCreateAPIView) queryset = Book.objects.all() serializer_class = BookSerializer class BookFilterView(generics.RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer
使用視圖組件的viewset進行接口邏輯優化
導入模塊 from rest_framework.viewset import ModelViewSet
設計url
re_path(r'books/$, views.BookView.as_view({
'get': 'list', 'post': 'create' })), re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({ 'get': 'retrieve', 'delete': 'destroy', 'put': 'update' }))
設計視圖類
class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
5 認證組件
cookie和session兩種方式能夠保存用戶信息,這兩種方式不一樣的是cookie保存在客戶端瀏覽器中,而session保存在服務器中,他們各有優缺點,配合起來使用,可將重要的敏感的信息存儲在session中,而在cookie中能夠存儲不太敏感的數據。
token稱之爲令牌。cookie、session和token都有其應用場景,沒有誰好誰壞,不過開發數據接口類的Web應用,目前用token仍是比較多的。
token認證步驟:
用戶登陸,服務器端獲取密碼,查詢用戶表,若是存在該用戶且第一次登陸(或者token過時), 生成token,不然返回錯誤信息
若是用戶不是第一次登陸,且token未過時,更新token值
建立倆個model,(token能夠存儲在user表中,建議存儲在user表中):
from django.db import models # Create your models here.
class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) user_type_entry = ( (1, 'Delux'), (2, 'SVIP'), (3, "VVIP") ) user_type = models.IntegerField(choices=user_type_entry) address = models.CharField(max_length=32) def __str__(self): return self.username class UserToken(models.Model): user = models.OneToOneField("User", on_delete=models.CASCADE) token = models.CharField(max_length=128)
由於涉及登陸認證,因此寫post方法接口,登陸都是post請求:
from django.http import JsonResponse from rest_framework.views import APIView from .models import User, Book, UserToken from .utils import get_token class UserView(APIView): def post(self, request): response = dict() try: username = request.data['username'] password = request.data['password'] user_instance = User.objects.filter( user_name=username, password=password ).first() if user_instance: access_token = get_token.generater_token() UserToken.objects.update_or_create(user=user_instance, defaults={ "token": access_token }) response["status_code"] = 200 response["status_message"] = "登陸成功" response["access_token"] = access_token response["user_role"] = user_instance.get_user_type_display() else: response["status_code"] = 201 response["status_message"] = "登陸失敗,用戶名或密碼錯誤"
except Exception as e: response["status_code"] = 202 response["status_message"] = str(e) return JsonResponse(response)
經過獲取隨機字符串的方法用來生成token值:
# -*- coding: utf-8 -*-
import uuid def generater_token(): random_str = ''.join(str(uuid.uuid4()).split('-')) return random_str
DRF認證組件的使用:
新建一個認證類,包含以後的認證邏輯:
class UserAuth(object): def authenticate_header(self, request): pass
def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.username, token_object.token else: raise APIException("認證失敗")
實現方式看上去很是簡單,到token表裏面查看token是否存在,而後根據這個信息,返回對應信息便可,而後,在須要認證經過才能訪問的數據接口裏面註冊認證類便可:
class BookView(ModelViewSet): authentication_classes = [UserAuth, UserAuth2] queryset = Book.objects.all() serializer_class = BookSerializer
多個認證類實現:
注意:若須要返回數據,請在最後一個認證類中返回,由於在前面返回,self.authentication()方法中會對返回值進行判斷,若不爲空,認證的過程就會終止. 多個認證類實現方式以下:
class UserAuth2(object): def authenticate(self, request): raise APIException("認證失敗") class UserAuth(object): def authenticate_header(self, request): pass
def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.username, token_object.token else: raise APIException("認證失敗") class BookView(ModelViewSet): authentication_classes = [UserAuth, UserAuth2]
簡化authenticate_header方法,以下:(繼承BaseAuthentication類便可)
from rest_framework.authentication import BaseAuthentication class UserAuth2(BaseAuthentication): def authenticate(self, request): raise APIException("認證失敗") class UserAuth(BaseAuthentication): def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.user_name, token_object.token else: raise APIException("認證失敗")
全局認證:
實現全部的數據接口都須要認證:
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES
若是認證類本身沒有authentication_classes,就會到settings中去找,經過這個機制,咱們能夠將認證類寫入到settings文件中便可實現全局認證:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'authenticator.utils.authentication.UserAuth', 'authenticator.utils.authentication.UserAuth2', ), }
6 權限組件
定義權限類:
class UserPerms(): message = "您沒有權限訪問該數據"
def has_permission(self, request, view): if request.user.user_type > 2: return True else: return False
一樣的邏輯,一樣的方式,只是執行權限的方法名與執行認證的方法名不同而已,名爲has_permission,而且須要將當前的視圖類傳遞給該方法。
視圖類中加入permission_classes變量:
class BookView(ModelViewSet): authentication_classes = [UserAuth] permission_classes = [UserPerms2] queryset = Book.objects.all() serializer_class = BookSerializer
7 頻率組件
8 url控制器組件
9 分頁器組件
10 響應器組件