在開發Web應用中,有兩種應用模式:html
先後端不分離前端
2.先後端分離python
爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。git
目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。github
rpc: 翻譯成中文:遠程過程調用[遠程服務調用].web
post請求django
action=get_all_student¶ms=301&sex=1json
接口多了,對應函數名和參數就多了,前端在請求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 | 增長學生 |
| GET | /students/1 | 獲取編號爲1的學生 |
| PUT | /students/1 | 修改編號爲1的學生 |
| DELETE | /students/1 | 刪除編號爲1的學生 |
事實上,咱們可使用任何一個框架均可以實現符合restful規範的API接口。
參考文檔:http://www.runoob.com/w3cnote/restful-architecture.html
api接口開發,最核心最多見的一個過程就是序列化,所謂序列化就是把數據轉換格式,序列化能夠分兩個階段:
序列化: 把咱們識別的數據轉換成指定的格式提供給別人。
例如:咱們在django中獲取到的數據默認是模型對象,可是模型對象數據沒法直接提供給前端或別的平臺使用,因此咱們須要把數據進行序列化,變成字符串或者json數據,提供給別人。
反序列化:把別人提供的數據轉換/還原成咱們須要的格式。
例如:前端js提供過來的json數據,對於python而言就是字符串,咱們須要進行反序列化換成模型類對象,這樣咱們才能把數據保存到數據庫中。
核心思想: 縮減編寫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 界面;
可擴展性,插件豐富
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)
pip install djangorestframework
在settings.py的INSTALLED_APPS中添加'rest_framework'。
INSTALLED_APPS = [ ... 'rest_framework', ]
接下來就可使用DRF進行開發了。在項目中若是使用rest_framework框架實現API接口,主要有如下三個步驟:
將請求的數據(如JSON格式)轉換爲模型類對象
操做數據庫
將模型類對象轉換爲響應的數據(如JSON格式)
注意,最好使用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")), ]
demo1 url:
from rest_framework.routers import DefaultRouter from .views import BookInfoAPIView urlpatterns = [] # 建立路由對象 routers = DefaultRouter() # 經過路由對象對視圖類進行路由生成 routers.register("books",BookInfoAPIView) urlpatterns+=routers.urls
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 = BookInfoSerializer
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.hname
運行項目後,可進行增刪改查操做:
在瀏覽器中輸入網址127.0.0.1:8000,能夠看到DRF提供的API Web瀏覽頁面:
點擊連接127.0.0.1:8000/books/ 能夠訪問獲取全部數據的接口(查看全部,添加)
在瀏覽器中輸入網址127.0.0.1:8000/books/d+/,能夠訪問獲取單一圖書信息的接口(id爲d+的圖書) (刪除.修改)
Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。
例如,咱們已有了一個數據庫模型類BookInfo
class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name='名稱') bpub_date = models.DateField(verbose_name='發佈日期', null=True) bread = models.IntegerField(default=0, verbose_name='閱讀量') bcomment = models.IntegerField(default=0, verbose_name='評論量') image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
咱們想爲這個模型類提供一個序列化器,能夠定義以下:
class BookInfoSerializer(serializers.Serializer): """圖書數據序列化器""" id = serializers.IntegerField(label='ID', read_only=True) btitle = serializers.CharField(label='名稱', max_length=20) bpub_date = serializers.DateField(label='發佈日期', required=False) bread = serializers.IntegerField(label='閱讀量', required=False) bcomment = serializers.IntegerField(label='評論量', required=False) image = serializers.ImageField(label='圖片', required=False)
注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。
定義好Serializer類後,就能夠建立Serializer對象了。
Serializer的構造方法爲:
Serializer(instance=None, data=empty, **kwarg)
說明:
1)用於序列化時,將模型類對象傳入instance參數
2)用於反序列化時,將要被反序列化的數據傳入data參數
3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如
serializer = AccountSerializer(account, context={'request': request})
經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。
使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠。
序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。
序列化器的字段聲明相似於咱們前面使用過的表單系統。
開發restful api時,序列化器會幫咱們把模型數據轉換成字典.
drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.
序列化器的使用分兩個階段:
在客戶端請求時,使用序列化器能夠完成對數據的反序列化。
在服務器響應時,使用序列化器能夠完成對數據的序列化。
drf-url:
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")), ]
ser-url:
from django.urls import path, re_path from . import views urlpatterns = [ path("books/",views.BookInfoView.as_view()), ]
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)
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="邏輯刪除")
序列化的表格能夠和反序列化的表公用,並且反序列化的表更增強大,由於還能驗證數據,因此通常只保留反序列化的序列化表,不過對於一些只讀的字段,可添加read_only 字段選項來避免
使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。
在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False。
驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。若是是非字段錯誤,能夠經過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。
驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。
在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。
drf-url:
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")), ]
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()), ]
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)
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 ######################################################################################
若是咱們想要使用序列化器對應的是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)
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("閱讀量小於評論量,數據太假了")
補充一些參數:
1.經常使用字段類型:
字段 | 字段構造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正則字段,驗證正則模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數 decimal_palces: 小數點位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices與Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
2.選項參數:
參數名稱 | 做用 |
---|---|
max_length | 最大長度 |
min_lenght | 最小長度 |
allow_blank | 是否容許爲空 |
trim_whitespace | 是否截斷空白字符 |
max_value | 最小值 |
min_value | 最大值 |
3.通用參數:
參數名稱 | 說明 |
---|---|
read_only | 代表該字段僅用於序列化輸出,默認False |
write_only | 代表該字段僅用於反序列化輸入,默認False |
required | 代表該字段在反序列化時必須輸入,默認True |
default | 反序列化時使用的默認值 |
allow_null | 代表該字段是否容許傳入None,默認False |
validators | 該字段使用的驗證器 |
error_messages | 包含錯誤編號與錯誤信息的字典 |
label | 用於HTML展現API頁面時,顯示的字段名稱 |
help_text | 用於HTML展現API頁面時,顯示的字段幫助提示信息 |