DRF之簡介以及序列化操作
在開發Web應用中,有兩種應用模式:
-
前後端不分離
2.前後端分離
2. api接口
為了在團隊內部形成共識、防止個人習慣差異引起的混亂,我們需要找到一種大家都覺得很好的接口實現規範,而且這種規範能夠讓後端寫的接口,用途一目了然,減少雙方之間的合作成本。
目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。
rpc: 翻譯成中文:遠程過程調用[遠程服務調用].
http://www.lufei.com/api
post請求
action=get_all_student¶ms=301&sex=1
接口多了,對應函數名和參數就多了,前端在請求api接口時,就會比較難找.容易出現重復的接口
restful: 翻譯成中文: 資源狀態轉換.把後端所有的數據/文件都看成資源.那麽接口請求數據,本質上來說就是對資源的操作了.
web項目中操作資源,無非就是增刪查改.所以要求在地址欄中聲明要操作的資源是什麽,然後通過http請求動詞來說明對資源進行哪一種操作.
POST http://www.lufei.com/api/students/ 添加數據
GET http://www.lufei.com/api/students/ 獲取所有學生
REST全稱是Representational State Transfer,中文意思是表述(編者註:通常譯為表征)性狀態轉移。 它首次出現在2000年Roy Fielding的博士論文中。
RESTful是一種定義Web API接口的設計風格,尤其適用於前後端分離的應用模式中。
這種風格的理念認為後端開發任務就是提供數據的,對外提供的是數據資源的訪問接口,所以在定義接口時,客戶端訪問的URL路徑就表示這種要操作的數據資源。
而對於數據資源分別使用POST、DELETE、GET、UPDATE等請求動作來表達對數據的增刪查改。
| 請求方法 | 請求地址 | 後端操作 |
| -------- | ----------- | ----------------- |
| GET | /students | 獲取所有學生 |
| POST | /students | 增加學生 |
| PUT | /students/1 | 修改編號為1的學生 |
| DELETE | /students/1 | 刪除編號為1的學生 |
事實上,我們可以使用任何一個框架都可以實現符合restful規範的API接口。
參考文檔:http://www.runoob.com/w3cnote/restful-architecture.html
4. 序列化
api接口開發,最核心最常見的一個過程就是序列化,所謂序列化就是把數據轉換格式,序列化可以分兩個階段:
序列化: 把我們識別的數據轉換成指定的格式提供給別人。
例如:我們在django中獲取到的數據默認是模型對象,但是模型對象數據無法直接提供給前端或別的平臺使用,所以我們需要把數據進行序列化,變成字符串或者json數據,提供給別人。
反序列化:把別人提供的數據轉換/還原成我們需要的格式。
例如:前端js提供過來的json數據,對於python而言就是字符串,我們需要進行反序列化換成模型類對象,這樣我們才能把數據保存到數據庫中。
5. Django Rest_Framework
核心思想: 縮減編寫api接口的代碼
Django REST framework是一個建立在Django基礎之上的Web 應用開發框架,可以快速的開發REST API接口應用。在REST framework中,提供了序列化器Serialzier的定義,可以幫助我們簡化序列化與反序列化的過程,不僅如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的編寫工作。REST framework還提供了認證、權限、限流、過濾、分頁、接口文檔等功能支持。REST framework提供了一個API 的Web可視化界面來方便查看測試接口。
中文文檔:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework
github: https://github.com/encode/django-rest-framework/tree/master
特點
-
提供了定義序列化器Serializer的方法,可以快速根據 Django ORM 或者其它庫自動序列化/反序列化;
-
提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫;
-
豐富的定制層級:函數視圖、類視圖、視圖集合到自動生成 API,滿足各種需要;
-
多種身份認證和權限認證方式的支持;[jwt]
-
內置了限流系統;
-
直觀的 API web 界面;
-
可擴展性,插件豐富
6. 環境安裝與配置
DRF需要以下依賴:
-
Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
-
Django (1.10, 1.11, 2.0)
DRF是以Django擴展應用的方式提供的,所以我們可以直接利用已有的Django環境而無需從新創建。(若沒有Django環境,需要先創建環境安裝Django)
6.1 安裝DRF
pip install djangorestframework
6.2 添加rest_framework應用
在settings.py的INSTALLED_APPS中添加‘rest_framework‘。
INSTALLED_APPS = [ ... ‘rest_framework‘, ]
接下來就可以使用DRF進行開發了。在項目中如果使用rest_framework框架實現API接口,主要有以下三個步驟:
-
將請求的數據(如JSON格式)轉換為模型類對象
-
操作數據庫
-
將模型類對象轉換為響應的數據(如JSON格式)
創建django項目:
註意,最好使用cmd窗口命令創建原生django項目,不要用pycharm自帶的工具創建,避免pycharm自身增加的一些配置,防止在項目合作開發時遇到合並代碼時出現問題;
django-admin.py startproject mysite
一個完整的使用模型序列化的示例:
url:
from django.contrib import admin from django.urls import path, include urlpatterns = [ path(‘admin/‘, admin.site.urls), path(‘api/‘, include("demo1.urls")), ]View Code
demo1 url:
from rest_framework.routers import DefaultRouter from .views import BookInfoAPIView urlpatterns = [] # 創建路由對象 routers = DefaultRouter() # 通過路由對象對視圖類進行路由生成 routers.register("books",BookInfoAPIView) urlpatterns+=routers.urlsView Code
demo1 view試圖:
from rest_framework.viewsets import ModelViewSet from demo1.models import BookInfo from .serializers import BookInfoSerializer # Create your views here. class BookInfoAPIView(ModelViewSet): # 當前視圖類所有方法使用得數據結果集是誰? queryset = BookInfo.objects.all() # 當前視圖類使用序列化器類是誰 serializer_class = BookInfoSerializerView Code
models:
from django.db import models # Create your models here. # Create your models here. #定義圖書模型類BookInfo class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name=‘圖書標題‘) bpub_date = models.DateField(verbose_name=‘出版時間‘) bread = models.IntegerField(default=0, verbose_name=‘閱讀量‘) bcomment = models.IntegerField(default=0, verbose_name=‘評論量‘) is_delete = models.BooleanField(default=False, verbose_name=‘邏輯刪除‘) class Meta: db_table = ‘tb_books‘ # 指明數據庫表名 verbose_name = ‘圖書‘ # 在admin站點中顯示的名稱 verbose_name_plural = verbose_name # 顯示的復數名稱 def __str__(self): """定義每個數據對象的顯示信息""" return "圖書:《"+self.btitle+"》" #定義英雄模型類HeroInfo class HeroInfo(models.Model): GENDER_CHOICES = ( (0, ‘男‘), (1, ‘女‘) ) hname = models.CharField(max_length=20, verbose_name=‘名稱‘) hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name=‘性別‘) hcomment = models.CharField(max_length=200, null=True, verbose_name=‘技能描述‘) hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name=‘所屬圖書‘) # 外鍵 is_delete = models.BooleanField(default=False, verbose_name=‘邏輯刪除‘) class Meta: db_table = ‘tb_heros‘ verbose_name = ‘英雄‘ verbose_name_plural = verbose_name def __str__(self): return self.hnameView Code
運行項目後,可進行增刪改查操作:
在瀏覽器中輸入網址127.0.0.1:8000,可以看到DRF提供的API Web瀏覽頁面:
from django.contrib import admin from django.urls import path, include urlpatterns = [ path(‘admin/‘, admin.site.urls), path(‘api/‘, include("demo1.urls")), path(‘ser/‘, include("ser.urls")), ]View Code
ser-url:
from django.urls import path, re_path from . import views urlpatterns = [ path("books/",views.BookInfoView.as_view()), ]View Code
views:
from django.http import JsonResponse from django.shortcuts import render from django.views import View from demo1.models import BookInfo from .serializers import BookInfoSerializer class BookInfoView(View): def get(self,request): # 操作數據庫 books = BookInfo.objects.all() # 創建序列化器對象 # 參數1: instance=要序列化的模型數據 # 參數2: data=要反序列化器的字典數據 # 參數3: many= 是否要序列化多個模型數據,多條數據many=True,默認一條數據 # 參數4: context=序列化器使用的上下文,字典類型數據,可以通過context把視圖中的數據,傳遞給序列化器內部使用 serializer = BookInfoSerializer(instance=books, many=True) # 通過 serializer.data 獲取序列化完成以後的數據 print(serializer.data) # 返回數據 return JsonResponse(serializer.data, safe=False)View Code
serialize:
############################################################################################################################### # 1. 序列化器的序列化階段使用 ############################################################################################################################### from rest_framework import serializers class BookInfoSerializer(serializers.Serializer): # # 自定義要序列化的字段 id = serializers.IntegerField(label="主鍵ID",read_only=True) btitle=serializers.CharField(label="圖書標題") bpub_date = serializers.DateField(label="出版日期") bread=serializers.IntegerField(label="閱讀量") bcomment=serializers.IntegerField(label="評論量") is_delete=serializers.BooleanField(label="邏輯刪除")View Code
from django.contrib import admin from django.urls import path, include urlpatterns = [ path(‘admin/‘, admin.site.urls), # path(‘api/‘, include("demo1.urls")), path(‘ser/‘, include("ser.urls")), ]View Code
ser-urls:
from django.urls import path, re_path from . import views urlpatterns = [ path("books2/", views.BookInfo2View.as_view()), re_path("books2/(?P<pk>\d+)/", views.BookInfo2View.as_view()), ]View Code
views:
from django.views import View from django.http import JsonResponse from django.http import QueryDict from .serializers import BookInfo2Serializer from demo1.models import BookInfo ############################################################################################################################### # 2 序列化器的反序列化階段使用 # 主要用戶驗證數據和字典數據轉換成模型 # 為了保證測試順利進行,我們在settings.py中關閉 csrf的中間件 # ‘django.middleware.csrf.CsrfViewMiddleware‘, ############################################################################################################################### class BookInfo2View(View): def get(self,request): # 操作數據庫 books = BookInfo.objects.all() # 創建序列化器對象 # 參數1: instance=要序列化的模型數據 # 參數2: data=要反序列化器的字典數據 # 參數3: many= 是否要序列化多個模型數據,多條數據many=True,默認一條數據 # 參數4: context=序列化器使用的上下文,字典類型數據,可以通過context把視圖中的數據,傳遞給序列化器內部使用 serializer = BookInfo2Serializer(instance=books, many=True) # 通過 serializer.data 獲取序列化完成以後的數據 print(serializer.data) # 返回數據 return JsonResponse(serializer.data, safe=False) def post(self, request): """添加一本圖書""" # 接受數據 data = request.POST # 反序列化 serializer = BookInfo2Serializer(data=data) # 1. 驗證數據 # raise_exception=True 把驗證的錯誤信息返回給客戶端,同時阻止程序繼續往下執行 serializer.is_valid(raise_exception=True) # is_valid調用驗證方式: 字段選項validators->自定義驗證方法[單字段]->自定義驗證方法[多字段] # 驗證成功後的數據 # print(serializer.validated_data) # 2. 轉換數據成模型,同步到數據庫中 result = serializer.save() # save會自動調用序列化器類裏面聲明的create/update方法,返回值是當前新增/更新的模型對象 # 響應數據 return JsonResponse(serializer.data) def put(self,request,pk): """更新一個圖書""" # 根據id主鍵獲取指定圖書信息 instance=BookInfo.objects.get(pk=pk) data = QueryDict(request.body) # 使用序列化器完成驗證和反序列化過程 # partial=True 接下裏在反序列化中允許部分數據更新 serializer = BookInfo2Serializer(instance=instance,data=data,partial=True) serializer.is_valid(raise_exception=True) # save之所以可以自動識別,什麽時候執行create ,什麽時候執行update # 主要是看創建序列化器對象時,是否有傳入instance參數, # 有instance參數,則save會調用序列化器內部的update方法 # 沒有instance參數,則save會調用序列化器內部的create方法 result = serializer.save() return JsonResponse(serializer.data)View Code
serialize:
############################################################################################################################### # 2 序列化器的反序列化階段使用 # 主要用戶驗證數據和字典數據轉換成模型 ############################################################################################################################### from rest_framework import serializers from demo1.models import BookInfo # 自定義驗證字段選項函數,很少用 def check_btitle(data): if data=="西廂記": raise serializers.ValidationError("西廂記也是禁書~") # 一定要返回數據 return data class BookInfo2Serializer(serializers.Serializer): # 自定義要反序列化的字段 id = serializers.IntegerField(label="主鍵ID",read_only=True) btitle = serializers.CharField(label="標題",required=True,min_length=1,max_length=20,validators=[check_btitle]) #通過validators=[check_btitle,]調用自定義選項函數 bpub_date=serializers.DateField(label="出版日期") bread=serializers.IntegerField(label="閱讀量",min_value=0) bcomment=serializers.IntegerField(label="評論量",default=0) # required=False 反序列化時, 當前字段可以不填 is_delete=serializers.BooleanField(label="邏輯刪除") # 自定義驗證方法[驗證單個字段,可以有多個方法] #寫法必須是 def validate_<字段名>(self,data): # data當前字段對應的值 def validate_btitle(self,data): # 例如,圖書名不能是紅樓夢 if data=="紅樓夢": # 拋出錯誤 raise serializers.ValidationError("紅樓夢是禁書~") # 驗證方法中,把數據值必須返回給字段,否則字段值為空 return data # 自定義驗證方法[驗證多個或者所有字段,只能出現一次] 寫法必須是validate(self,data) def validate(self,data): # data 這個是所有字段的內容,字典類型 bread = data.get("bread") bcomment = data.get("bcomment") if bread>=bcomment: return data raise serializers.ValidationError("閱讀量小於評論量,數據太假了") def create(self,validated_data): """ 保存數據,把字典轉換成模型 validated_data 客戶端提交過來,並經過驗證的數據 """ instance = BookInfo.objects.create( btitle = validated_data.get("btitle"), bread = validated_data.get("bread"), bcomment = validated_data.get("bcomment"), bpub_date = validated_data.get("bpub_date"), is_delete = validated_data.get("is_delete"), ) #返回模型對象 return instance def update(self,instance,validated_data): """更新數據 instance 本次更新操作的模型對象 validated_data 客戶端提交過來,並經過驗證的數據 """ instance.btitle=validated_data.get(‘btitle‘) instance.bread=validated_data.get(‘bread‘) instance.bcomment=validated_data.get(‘bcomment‘) instance.bpub_date=validated_data.get(‘bpub_date‘) instance.is_delete=validated_data.get(‘is_delete‘) # 調用ORM的保存更新操作 instance.save() # 返回模型對象 return instance ######################################################################################View Code
模型類序列化:相當於modelform組件....用法等
如果我們想要使用序列化器對應的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創建一個Serializer類。
ModelSerializer與常規的Serializer相同,但提供了:
-
基於模型類自動生成一系列字段
-
基於模型類自動為Serializer生成validators,比如unique_together
-
包含默認的create()和update()的實現
demo:
views:
############################################################################################################################### # 3 模型序列化器 # 1. 可以幫我們自動完成字段的聲明[主要是從模型中的字段聲明裏面提取過來] # 2. 模型序列化器也可以幫我們聲明了create和update方法的代碼 ############################################################################################################################### from django.views import View from django.http import JsonResponse from .serializers import BookInfoModelSerializer class BookInfo3View(View): def post(self, request): data = request.POST serializer = BookInfoModelSerializer(data=data) serializer.is_valid(raise_exception=True) result = serializer.save() # 響應數據 return JsonResponse(serializer.data) def put(self, request, pk): """更新一個圖書""" book = BookInfo.objects.get(pk=pk) # 獲取put提交的數據 data = QueryDict(request.body) #允許部分更新partial=True serializer = BookInfoModelSerializer(instance=book, data=data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() # 響應數據 return JsonResponse(serializer.data)View Code
serialize:
###################################################################################### from rest_framework import serializers from demo1.models import BookInfo class BookInfoModelSerializer(serializers.ModelSerializer): class Meta: model = BookInfo # fields = ["id", "btitle"] fields=‘__all__‘ # 可以給模型序列化器裏面指定的字段設置限制選項 extra_kwargs = { "bread": {"min_value": 0, "required": True}, } def validate_btitle(self,data): # 例如,圖書名不能是紅樓夢 if data=="紅樓夢": # 拋出錯誤 raise serializers.ValidationError("紅樓夢是禁書~") # 驗證方法中,把數據值必須返回給字段,否則字段值為空 return data # 自定義驗證方法[驗證多個或者所有字段,只能出現一次] def validate(self,data): # data 這個是所有字段的內容,字典類型 bread = data.get("bread") bcomment = data.get("bcomment") if bread>=bcomment: return data raise serializers.ValidationError("閱讀量小於評論量,數據太假了")View Code
DRF之簡介以及序列化操作