DRF

1. Web應用模式

在開發Web應用中,有兩種應用模式:css

  1. 先後端不分離

先後端不分離

  1. 先後端分離

先後端分離

2. api接口

爲了在團隊內部造成共識、防止我的習慣差別引發的混亂,咱們須要找到一種你們都以爲很好的接口實現規範,並且這種規範可以讓後端寫的接口,用途一目瞭然,減小雙方之間的合做成本。html

目前市面上大部分公司開發人員使用的接口服務架構主要有:restful、rpc。前端

rpc: 翻譯成中文:遠程過程調用[遠程服務調用].python

http://www.lufei.com/apimysql

post請求linux

action=get_all_student&params=301&sex=1git

接口多了,對應函數名和參數就多了,前端在請求api接口時,就會比較難找.容易出現重複的接口github

restful: 翻譯成中文: 資源狀態轉換.web

把後端全部的數據/文件都當作資源.sql

那麼接口請求數據,本質上來講就是對資源的操做了.

web項目中操做資源,無非就是增刪查改.因此要求在地址欄中聲明要操做的資源是什麼,而後經過http請求動詞來講明對資源進行哪種操做.

POST http://www.lufei.com/api/students/ 添加學生數據

GET http://www.lufei.com/api/students/ 獲取全部學生

DELETE http://www.lufei.com/api/students/ 刪除1個學生

3. RESTful API規範

restful

REST全稱是Representational State Transfer,中文意思是表述(編者注:一般譯爲表徵)性狀態轉移。 它首次出如今2000年Roy Fielding的博士論文中。

RESTful是一種定義Web API接口的設計風格,尤爲適用於先後端分離的應用模式中。

這種風格的理念認爲後端開發任務就是提供數據的,對外提供的是數據資源的訪問接口,因此在定義接口時,客戶端訪問的URL路徑就表示這種要操做的數據資源。

而對於數據資源分別使用POST、DELETE、GET、UPDATE等請求動做來表達對數據的增刪查改。

請求方法 請求地址 後端操做
GET /students 獲取全部學生
POST /students 增長學生
GET /students/ 獲取編號爲pk的學生
PUT /students/ 修改編號爲pk的學生
DELETE /students/ 刪除編號爲pk的學生

事實上,咱們能夠使用任何一個框架均可以實現符合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可視化界面來方便查看測試接口。

drf_logo

中文文檔: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

前提是已經安裝了django,建議安裝在虛擬環境

# mkvirtualenv drfdemo -p python3
# pip install django

pip install djangorestframework
pip install pymysql

linux 複製 shift+insert

6.1.1 建立django項目

cd ~/Desktop
django-admin startproject drfdemo

1557022536078

使用pycharm打開項目,設置虛擬環境的解析器,並修改manage.py中的後綴參數

6.2 添加rest_framework應用

settings.pyINSTALLED_APPS中添加'rest_framework'。

INSTALLED_APPS = [
    ...
    'rest_framework',
]

接下來就可使用DRF提供的功能進行api接口開發了。在項目中若是使用rest_framework框架實現API接口,主要有如下三個步驟:

  • 將請求的數據(如JSON格式)轉換爲模型類對象
  • 操做數據庫
  • 將模型類對象轉換爲響應的數據(如JSON格式)

接下來,咱們快速體驗下四天後咱們學習完成drf之後的開發代碼。接下來代碼不須要理解,看步驟。

6.3 體驗drf徹底簡寫代碼的過程

6.3.1. 建立模型操做類

class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名")
    sex = models.BooleanField(default=1,verbose_name="性別")
    age = models.IntegerField(verbose_name="年齡")
    class_null = models.CharField(max_length=5,verbose_name="班級編號")
    description = models.TextField(max_length=1000,verbose_name="個性簽名")

    class Meta:
        db_table="tb_student"
        verbose_name = "學生"
        verbose_name_plural = verbose_name

爲了方便測試,因此咱們能夠先建立一個數據庫。

mysql -uroot -p;
create database students charset=utf8;

1557023744365

6.3.1.1 執行數據遷移

把students子應用添加到INSTALL_APPS中

1557023819604

初始化數據庫鏈接

安裝pymysql
pip install pymysql

主引用中__init__.py設置使用pymysql做爲數據庫驅動

import pymysql

pymysql.install_as_MySQLdb()

settings.py配置文件中設置mysql的帳號密碼

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # },
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "students",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "root",
        "PASSWORD":"123",
    }
}

終端下,執行數據遷移。

python manage.py makemigrations
python manage.py migrate

錯誤列表

# 執行數據遷移 python manage.py makemigrations 報錯以下:

1557024349366

解決方案:

註釋掉 backends/mysql/base.py中的35和36行代碼。

1557025991751

# 執行數據遷移發生如下錯誤:

1557026113769

解決方法:

backends/mysql/operations.py146行裏面新增一個行代碼:

1557026224431

6.3.2. 建立序列化器

例如,在django項目中建立學生子應用。

python manage.py startapp students

在syudents應用目錄中新建serializers.py用於保存該應用的序列化器。

建立一個StudentModelSerializer用於序列化與反序列化。

# 建立序列化器類,回頭會在試圖中被調用
class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
  • model 指明該序列化器處理的數據字段從模型類Student參考生成
  • fields 指明該序列化器包含模型類中的哪些字段,'all'指明包含全部字段

6.3.3. 編寫視圖

在students應用的views.py中建立視圖StudentViewSet,這是一個視圖集合。

from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
# Create your views here.
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
  • queryset 指明該視圖集在查詢數據時使用的查詢集
  • serializer_class 指明該視圖在進行序列化或反序列化時使用的序列化器

6.3.4. 定義路由

在students應用的urls.py中定義路由信息。

from . import views
from rest_framework.routers import DefaultRouter

# 路由列表
urlpatterns = []

router = DefaultRouter()  # 能夠處理視圖的路由器
router.register('students', views.StudentViewSet)  # 向路由器中註冊視圖集

urlpatterns += router.urls  # 將路由器中的因此路由信息追到到django的路由列表中

最後把students子應用中的路由文件加載到總路由文件中.

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("stu/",include("students.urls")),
]

6.3.5. 運行測試

運行當前程序(與運行Django同樣)

python manage.py runserver

在瀏覽器中輸入網址127.0.0.1:8000,能夠看到DRF提供的API Web瀏覽頁面:

1557027948031

1)點擊連接127.0.0.1:8000/stu/students 能夠訪問獲取全部數據的接口,呈現以下頁面:

1557027878963

2)在頁面底下表單部分填寫學生信息,能夠訪問添加新學生的接口,保存學生信息:

1557027999506

點擊POST後,返回以下頁面信息:

1557028072470

3)在瀏覽器中輸入網址127.0.0.1:8000/stu/students/5/,能夠訪問獲取單一學生信息的接口(id爲5的學生),呈現以下頁面:

1557028115925

4)在頁面底部表單中填寫學生信息,能夠訪問修改學生的接口

1557028168350

點擊PUT,返回以下頁面信息:

1557028208243

5)點擊DELETE按鈕,能夠訪問刪除學生的接口

1557028242637

返回,以下頁面:

1557028266190

7. 序列化器-Serializer

做用:

  1. 序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串
  2. 反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型
  3. 反序列化,完成數據校驗功能

7.1 定義序列化器

Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer

接下來,爲了方便演示序列化器的使用,咱們先建立一個新的子應用sers

python manage.py startapp sers

咱們已有了一個數據庫模型類students/models.py

models.py

from django.db import models

# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:帳號不能爲空!")
    sex = models.BooleanField(default=True,verbose_name="性別")
    age = models.IntegerField(verbose_name="年齡")
    class_null = models.CharField(max_length=5,verbose_name="班級編號")
    description = models.TextField(verbose_name="個性簽名")

    class Meta:
        db_table="tb_student"
        verbose_name = "學生"
        verbose_name_plural = verbose_name

咱們想爲這個模型類提供一個序列化器,能夠定義以下:

from rest_framework import serializers

# 聲明序列化器,全部的序列化器都要直接或者間接繼承於 Serializer
# 其中,ModelSerializer是Serializer的子類,ModelSerializer在Serializer的基礎上進行了代碼簡化
class StudentSerializer(serializers.Serializer):
    """學生信息序列化器"""
    # 1. 須要進行數據轉換的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()

    # 2. 若是序列化器集成的是ModelSerializer,則須要聲明調用的模型信息

    # 3. 驗證代碼

    # 4. 編寫添加和更新模型的代碼

注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。

經常使用字段類型

字段 字段構造方式
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(max*length=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=)

選項參數:

參數名稱 做用
max_length 最大長度
min_lenght 最小長度
allow_blank 是否容許爲空
trim_whitespace 是否截斷空白字符
max_value 最小值
min_value 最大值

通用參數:

參數名稱 說明
read_only 代表該字段僅用於序列化輸出,默認False
write_only 代表該字段僅用於反序列化輸入,默認False
required 代表該字段在反序列化時必須輸入,默認True
default 反序列化時使用的默認值
allow_null 代表該字段是否容許傳入None,默認False
validators 該字段使用的驗證器
error_messages 包含錯誤編號與錯誤信息的字典
label 用於HTML展現API頁面時,顯示的字段名稱
help_text 用於HTML展現API頁面時,顯示的字段幫助提示信息

7.2 建立Serializer對象

定義好Serializer類後,就能夠建立Serializer對象了。

Serializer的構造方法爲:

Serializer(instance=None, data=empty, **kwarg)

說明:

1)用於序列化時,將模型類對象傳入instance參數

2)用於反序列化時,將要被反序列化的數據傳入data參數

3)除了instancedata參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如

serializer = AccountSerializer(account, context={'request': request})

經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。

  1. 使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠。
  2. 序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來
  3. 序列化器的字段聲明相似於咱們前面使用過的表單系統。
  4. 開發restful api時,序列化器會幫咱們把模型數據轉換成字典.
  5. drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.

7.3 序列化器的使用

序列化器的使用分兩個階段:

  1. 在客戶端請求時,使用序列化器能夠完成對數據的反序列化。
  2. 在服務器響應時,使用序列化器能夠完成對數據的序列化。

7.3.1 序列化

7.3.1.1 基本使用

1) 先查詢出一個學生對象

from students.models import Student

student = Student.objects.get(id=3)

2) 構造序列化器對象

from .serializers import StudentSerializer

serializer = StudentSerializer(instance=student)

3)獲取序列化數據

經過data屬性能夠獲取序列化後的數據

serializer.data
# {'id': 4, 'name': '小張', 'age': 18, 'sex': True, 'description': '猴賽雷'}

完整視圖代碼:

views.py

from django.views import View
from students.models import Student
from .serializers import StudentSerializer
from django.http.response import JsonResponse

class StudentView(View):
    """使用序列化器序列化轉換單個模型數據"""
    def get(self,request,pk):
        # 獲取數據
        student = Student.objects.get(pk=pk)
        # 數據轉換[序列化過程]
        serializer = StudentSerializer(instance=student)
        print(serializer.data)
        # 響應數據
        return JsonResponse(serializer.data)

4)若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明

"""使用序列化器序列化轉換多個模型數據"""
    def get(self,request):
        # 獲取數據
        student_list = Student.objects.all()

        # 轉換數據[序列化過程]
        # 若是轉換多個模型對象數據,則須要加上many=True
        serializer = StudentSerializer(instance=student_list,many=True)
        print( serializer.data ) # 序列化器轉換後的數據

        # 響應數據給客戶端
        # 返回的json數據,若是是列表,則須要聲明safe=False
        return JsonResponse(serializer.data,safe=False)
    
    
    # 訪問結果:
    # [OrderedDict([('id', 1), ('name', 'xiaoming'), ('age', 20), ('sex', True), ('description', '測試')]), OrderedDict([('id', 2), ('name', 'xiaohui'), ('age', 22), ('sex', True), ('description', '後面來的測試')]), OrderedDict([('id', 4), ('name', '小張'), ('age', 18), ('sex', True), ('description', '猴賽雷')])]

7.3.2 反序列化

7.3.2.1 數據驗證

使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。

在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False。

驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。若是是非字段錯誤,能夠經過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。

驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。

在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。

如咱們前面定義過的BookInfoSerializer

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)

經過構造序列化器對象,並將要反序列化的數據傳遞給data構造參數,進而進行驗證

測試:

from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # 返回False
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data  # {}

data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.errors  # {}
serializer.validated_data  #  OrderedDict([('btitle', 'python')])

is_valid()方法還能夠在驗證失敗時拋出異常serializers.ValidationError,能夠經過傳遞raise_exception=True參數開啓,REST framework接收到此異常,會向前端返回HTTP 400 Bad Request響應。

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

若是以爲這些還不夠,須要再補充定義驗證行爲,可使用如下三種方法:

1) validate_字段名

<field_name>字段進行驗證,如

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...

    def validate_btitle(self, value):
        if 'django' not in value.lower():
            raise serializers.ValidationError("圖書不是關於Django的")
        return value

測試

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}
2) validate

在序列化器中須要同時對多個字段進行比較驗證時,能夠定義validate方法來驗證,如

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...

    def validate(self, attrs):
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        if bread < bcomment:
            raise serializers.ValidationError('閱讀量小於評論量')
        return attrs

測試

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=data)
s.is_valid()  # False
s.errors
#  {'non_field_errors': [ErrorDetail(string='閱讀量小於評論量', code='invalid')]}
3) validators

在字段中添加validators選項參數,也能夠補充驗證行爲,如

def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("圖書不是關於Django的")

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
    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)

測試:

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='圖書不是關於Django的', code='invalid')]}

7.3.2.2 反序列化-保存數據

前面的驗證數據成功後,咱們可使用序列化器來完成數據反序列化的過程.這個過程能夠把數據轉成模型類對象.

能夠經過實現create()和update()兩個方法來實現。

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance爲要更新的對象實例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        return instance

若是須要在返回數據對象的時候,也將數據保存到數據庫中,則能夠進行以下修改

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance爲要更新的對象實例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        instance.save()
        return instance

實現了上述兩個方法後,在反序列化數據的時候,就能夠經過save()方法返回一個數據對象實例了

book = serializer.save()

若是建立序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,若是傳遞了instance實例,則調用save()方法的時候,update()被調用

from db.serializers import BookInfoSerializer
data = {'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 封神演義>

from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid()  # True
serializer.save()  # <BookInfo: 倚天劍>
book.btitle  # '倚天劍'

7.3.2.3 附加說明

1) 在對序列化器進行save()保存時,能夠額外傳遞數據,這些數據能夠在create()和update()中的validated_data參數獲取到

# request.user 是django中記錄當前登陸用戶的模型對象
serializer.save(owner=request.user)

2)默認序列化器必須傳遞全部required的字段,不然會拋出驗證異常。但是咱們可使用partial參數來容許部分字段更新

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

7.3.3 模型類序列化器

若是咱們想要使用序列化器對應的是Django的模型類,DRF爲咱們提供了ModelSerializer模型類序列化器來幫助咱們快速建立一個Serializer類

ModelSerializer與常規的Serializer相同,但提供了:

  • 基於模型類自動生成一系列字段
  • 基於模型類自動爲Serializer生成validators,好比unique_together
  • 包含默認的create()和update()的實現

7.3.3.1 定義

好比咱們建立一個BookInfoSerializer

class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        fields = '__all__'
  • model 指明參照哪一個模型類
  • fields 指明爲模型類的哪些字段生成

咱們能夠在python manage.py shell中查看自動生成的BookInfoSerializer的具體實現

>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
    id = IntegerField(label='ID', read_only=True)
    btitle = CharField(label='名稱', max_length=20)
    bpub_date = DateField(allow_null=True, label='發佈日期', required=False)
    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
    image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

7.3.3.2 指定字段

1) 使用fields來明確字段,__all__表名包含全部字段,也能夠寫明具體哪些字段,如

class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date')

2) 使用exclude能夠明確排除掉哪些字段

class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        exclude = ('image',)

3) 顯示指明字段,如:

class HeroInfoSerializer(serializers.ModelSerializer):
    hbook = BookInfoSerializer()

    class Meta:
        model = HeroInfo
        fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')

4) 指明只讀字段

能夠經過read_only_fields指明只讀字段,即僅用於序列化輸出的字段

class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        read_only_fields = ('id', 'bread', 'bcomment')

7.3.3.3 添加額外參數

咱們可使用extra_kwargs參數爲ModelSerializer添加或修改原有的選項參數

class BookInfoSerializer(serializers.ModelSerializer):
    """圖書數據序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        extra_kwargs = {
            'bread': {'min_value': 0, 'required': True},
            'bcomment': {'min_value': 0, 'required': True},
        }

# BookInfoSerializer():
#    id = IntegerField(label='ID', read_only=True)
#    btitle = CharField(label='名稱', max_length=20)
#    bpub_date = DateField(allow_null=True, label='發佈日期', required=False)
#    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
#    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)

8. 類視圖[class view]

django中一共提供了兩種視圖:分別是函數視圖[function view]和類視圖[class view]

# 函數視圖
def login(request):
    """登陸功能"""
    # 登陸功能代碼
    return Response({「message」:"ok"})

接下來,方便學習,因此咱們建立一個新的子應用clsview

python manage.py startapp clsview

函數視圖,實現功能,須要手動判斷用戶的請求動做,並且當函數視圖數量多了,就不要概括整理。

"""函數視圖的登陸功能"""
from django.http import HttpResponse
def login_form(request):
    """顯示登陸頁面"""
    html = """
        <form method="post" action="/clsview/login_data/">
        帳號: <input type="text" name="usernane"><br><br>
        密碼: <input type="password" name="password"><br><br>
        <input type="submit" value="登陸">
        </form>
    """
    return HttpResponse(html)

    
def login_data(request):
    """驗證登陸"""
    print( request.POST )

    return HttpResponse("登陸成功")



""""路由代碼"""""
from django.urls.conf import path
from . import views
urlpatterns = [
    path(r"login_form/",views.login_form),
    path(r"login_data/",views.login_data),
]

類視圖,能夠實現django自動根據用戶的http請求動做,自動識別執行對應名稱的視圖方法。

form django.views import View
class MemberView(View):
    def get(self,request):
        """獲取用戶數據"""
        ...
        
    def post(self,request):
        """添加用戶數據"""
        ...
        
    def put(self,request):
        """修改用戶數據"""
        ...
        
    def delete(self,request):
        """刪除用戶數據"""
        ....

代碼:

from django.http import HttpResponse
from django.views import View
class LoginView(View):
    def get(self,request):
        """顯示登陸頁面"""
        html = """
            <form method="post" action="/clsview/login_data/">
            帳號: <input type="text" name="usernane"><br><br>
            密碼: <input type="password" name="password"><br><br>
            <input type="submit" value="登陸">
            </form>
        """
        return HttpResponse(html)

    def post(self,request):
        """處理登陸驗證"""
        print( request.POST )

        return HttpResponse("登陸成功")

類視圖核心的實現代碼就是as_view和dispatch方法

類視圖中的視圖方法都是固定名稱,只能是http請求動做的小寫名稱

9. 視圖

drf除了在數據序列化部分簡寫代碼之外,還在視圖中提供了簡寫操做。因此在django原有的django.views.View類基礎上,drf封裝了多個子類出來提供給咱們使用。

Django REST framwork 提供的視圖的主要做用:

  • 控制序列化器的執行(檢驗、保存、轉換數據)
  • 控制數據庫查詢的執行
  • 調用請求類和響應類[這兩個類也是由drf幫咱們再次擴展了一些功能類。]

爲了方便咱們學習,因此先建立一個子應用req

python manage.py startapp req

9.1. 請求與響應

9.1.1 Request

REST framework 傳入視圖的request對象再也不是Django默認的HttpRequest對象,而是REST framework提供的擴展了HttpRequest類的Request類的對象。

REST framework 提供了Parser解析器,在接收到請求後會自動根據Content-Type指明的請求數據類型(如JSON、表單等)將請求數據進行parse解析,解析爲類字典[QueryDict]對象保存到Request對象中。

Request對象的數據是自動根據前端發送數據的格式進行解析以後的結果。

不管前端發送的哪一種格式的數據,咱們均可以以統一的方式讀取數據。

9.1.1.1 經常使用屬性

1).data

request.data 返回解析以後的請求體數據。相似於Django中標準的request.POSTrequest.FILES屬性,但提供以下特性:

  • 包含了解析以後的文件和非文件數據
  • 包含了對POST、PUT、PATCH請求方式解析後的數據
  • 利用了REST framework的parsers解析器,不只支持表單類型數據,也支持JSON數據
2).query_params

request.query_params與Django標準的request.GET相同,只是更換了更正確的名稱而已。

9.1.2 Response

rest_framework.response.Response

REST framework提供了一個響應類Response,使用該類構造響應對象時,響應的具體數據內容會被轉換(render渲染)成符合前端需求的類型

REST framework提供了Renderer 渲染器,用來根據請求頭中的Accept(接收數據類型聲明)來自動轉換響應數據到對應格式。若是前端請求中未進行Accept聲明,則會採用默認方式處理響應數據,咱們能夠經過配置來修改默認響應格式。

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默認響應渲染類
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 瀏覽API渲染器
    )
}

9.1.2.1 構造方式

Response(data, status=None, template_name=None, headers=None, content_type=None)

data數據不要是render處理以後的數據,只需傳遞python的內建類型數據便可,REST framework會使用renderer渲染器處理data

data不能是複雜結構的數據,如Django的模型類對象,對於這樣的數據咱們可使用Serializer序列化器序列化處理後(轉爲了Python字典類型)再傳遞給data參數。

參數說明:

  • data: 爲響應準備的序列化處理後的數據;
  • status: 狀態碼,默認200;
  • template_name: 模板名稱,若是使用HTMLRenderer 時需指明;
  • headers: 用於存放響應頭信息的字典;
  • content_type: 響應數據的Content-Type,一般此參數無需傳遞,REST framework會根據前端所需類型數據來設置該參數。

9.1.2.2 經常使用屬性

1).data

傳給response對象的序列化後,但還沒有render處理的數據

2).status_code

狀態碼的數字

3).content

通過render處理後的響應數據

9.1.2.3 狀態碼

爲了方便設置狀態碼,REST framewrok在rest_framework.status模塊中提供了經常使用狀態碼常量。

1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4)客戶端錯誤 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5)服務器錯誤 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

9.2 視圖

REST framework 提供了衆多的通用視圖基類與擴展類,以簡化視圖的編寫。

9.2.1 2個視圖基類

9.2.1.1 APIView

rest_framework.views.APIView

APIView是REST framework提供的全部視圖的基類,繼承自Django的View父類

APIViewView的不一樣之處在於:

  • 傳入到視圖方法中的是REST framework的Request對象,而不是Django的HttpRequeset對象;
  • 視圖方法能夠返回REST framework的Response對象,視圖會爲響應數據設置(render)符合前端要求的格式;
  • 任何APIException異常都會被捕獲到,而且處理成合適的響應信息;
  • 在進行dispatch()分發前,會對請求進行身份認證、權限檢查、流量控制

支持定義的類屬性

  • authentication_classes 列表或元祖,身份認證類
  • permissoin_classes 列表或元祖,權限檢查類
  • throttle_classes 列表或元祖,流量控制類

APIView中仍以常規的類視圖定義方法來實現get() 、post() 或者其餘請求方式的方法。

舉例:

from rest_framework.views import APIView
from rest_framework.response import Response

# url(r'^students/$', views.StudentsAPIView.as_view()),
class StudentsAPIView(APIView):
    def get(self, request):
        data_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=data_list, many=True)
        return Response(serializer.data)

9.2.1.2 GenericAPIView[通用視圖類]

rest_framework.generics.GenericAPIView

繼承自APIVIew主要增長了操做序列化器和數據庫查詢的方法,做用是爲下面Mixin擴展類的執行提供方法支持。一般在使用時,可搭配一個或多個Mixin擴展類。

提供的關於序列化器使用的屬性與方法

  • 屬性:

    • serializer_class 指明視圖使用的序列化器
  • 方法:

    • get_serializer_class(self)

      當出現一個視圖類中調用多個序列化器時,那麼能夠經過條件判斷在get_serializer_class方法中經過返回不一樣的序列化器類名就可讓視圖方法執行不一樣的序列化器對象了。

      返回序列化器類,默認返回serializer_class,能夠重寫,例如:

      def get_serializer_class(self):
          if self.request.user.is_staff:
              return FullAccountSerializer
          return BasicAccountSerializer
    • get_serializer(self, args, *kwargs)

      返回序列化器對象,主要用來提供給Mixin擴展類使用,若是咱們在視圖中想要獲取序列化器對象,也能夠直接調用此方法。

      注意,該方法在提供序列化器對象的時候,會向序列化器對象的context屬性補充三個數據:request、format、view,這三個數據對象能夠在定義序列化器時使用。

      • request 當前視圖的請求對象
      • view 當前請求的類視圖對象
      • format 當前請求指望返回的數據格式

提供的關於數據庫查詢的屬性與方法

  • 屬性:

    • queryset 指明使用的數據查詢集
  • 方法:

    • get_queryset(self)

      返回視圖使用的查詢集,主要用來提供給Mixin擴展類使用,是列表視圖與詳情視圖獲取數據的基礎,默認返回queryset屬性,能夠重寫,例如:

      def get_queryset(self):
          user = self.request.user
          return user.accounts.all()
    • get_object(self)

      返回詳情視圖所需的模型類數據對象,主要用來提供給Mixin擴展類使用。

      在試圖中能夠調用該方法獲取詳情信息的模型類對象。

      若詳情訪問的模型類對象不存在,會返回404。

      該方法會默認使用APIView提供的check_object_permissions方法檢查當前對象是否有權限被訪問。

      舉例:

      # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
      class BookDetailView(GenericAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          def get(self, request, pk):
              book = self.get_object() # get_object()方法根據pk參數查找queryset中的數據對象
              serializer = self.get_serializer(book)
              return Response(serializer.data)

其餘能夠設置的屬性

  • pagination_class 指明分頁控制類
  • filter_backends 指明過濾控制後端

爲了方便學習上面的GenericAPIView通用視圖類,咱們新建一個子應用。

python manage.py startapp gen

代碼:

from rest_framework.generics import GenericAPIView

from students.models import Student
from .serializers import StudentModelSerializer, StudentModel2Serializer
from rest_framework.response import Response

class StudentsGenericAPIView(GenericAPIView):
    # 本次視圖類中要操做的數據[必填]
    queryset = Student.objects.all()
    # 本次視圖類中要調用的默認序列化器[選填]
    serializer_class = StudentModelSerializer

    def get(self, request):
        """獲取全部學生信息"""
        serializer = self.get_serializer(instance=self.get_queryset(), many=True)

        return Response(serializer.data)

    def post(self,request):

        data = request.data

        serializer = self.get_serializer(data=data)

        serializer.is_valid(raise_exception=True)

        instance = serializer.save()

        serializer = self.get_serializer(instance=instance)

        return Response(serializer.data)


class StudentGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()

    serializer_class = StudentModelSerializer

    def get_serializer_class(self):
        """重寫獲取序列化器類的方法"""
        if self.request.method == "GET":
            return StudentModel2Serializer
        else:
            return StudentModelSerializer

    # 在使用GenericAPIView視圖獲取或操做單個數據時,視圖方法中的表明主鍵的參數最好是pk
    def get(self,request,pk):
        """獲取一條數據"""
        serializer = self.get_serializer(instance=self.get_object())

        return Response(serializer.data)

    def put(self,request,pk):

        data = request.data

        serializer = self.get_serializer(instance=self.get_object(),data=data)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        serializer = self.get_serializer(instance=self.get_object())

        return Response(serializer.data)

序列化器類:

from rest_framework import serializers

from students.models import Student

class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model= Student
        fields = "__all__"


class StudentModel2Serializer(serializers.ModelSerializer):
    class Meta:
        model= Student
        fields = ("name","class_null")

9.2.2 5個視圖擴展類

做用:

提供了幾種後端視圖(對數據資源進行曾刪改查)處理流程的實現,若是須要編寫的視圖屬於這五種,則視圖能夠經過繼承相應的擴展類來複用代碼,減小本身編寫的代碼量。

這五個擴展類須要搭配GenericAPIView父類,由於五個擴展類的實現須要調用GenericAPIView提供的序列化器與數據庫查詢的方法。

1)ListModelMixin

列表視圖擴展類,提供list(request, *args, **kwargs)方法快速實現列表視圖,返回200狀態碼。

該Mixin的list方法會對數據進行過濾和分頁。

源代碼:

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        # 過濾
        queryset = self.filter_queryset(self.get_queryset())
        # 分頁
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        # 序列化
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

舉例:

from rest_framework.mixins import ListModelMixin

class BookListView(ListModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request):
        return self.list(request)

2)CreateModelMixin

建立視圖擴展類,提供create(request, *args, **kwargs)方法快速實現建立資源的視圖,成功返回201狀態碼。

若是序列化器對前端發送的數據驗證失敗,返回400錯誤。

源代碼:

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        # 獲取序列化器
        serializer = self.get_serializer(data=request.data)
        # 驗證
        serializer.is_valid(raise_exception=True)
        # 保存
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

3)RetrieveModelMixin

詳情視圖擴展類,提供retrieve(request, *args, **kwargs)方法,能夠快速實現返回一個存在的數據對象

若是存在,返回200, 不然返回404。

源代碼:

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 獲取對象,會檢查對象的權限
        instance = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

舉例:

class BookDetailView(RetrieveModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        return self.retrieve(request)

4)UpdateModelMixin

更新視圖擴展類,提供update(request, *args, **kwargs)方法,能夠快速實現更新一個存在的數據對象

同時也提供partial_update(request, *args, **kwargs)方法,能夠實現局部更新。****

成功返回200,序列化器校驗數據失敗時,返回400錯誤。

源代碼:

class UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

5)DestroyModelMixin

刪除視圖擴展類,提供destroy(request, *args, **kwargs)方法,能夠快速實現刪除一個存在的數據對象。

成功返回204,不存在返回404。

源代碼:

class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

使用GenericAPIView和視圖擴展類,實現api接口,代碼:

"""GenericAPIView結合視圖擴展類實現api接口"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class Students2GenericAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
    # 本次視圖類中要操做的數據[必填]
    queryset = Student.objects.all()
    # 本次視圖類中要調用的默認序列化器[玄天]
    serializer_class = StudentModelSerializer

    def get(self, request):
        """獲取多個學生信息"""
        return self.list(request)

    def post(self,request):
        """添加學生信息"""
        return self.create(request)


from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student2GenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()

    serializer_class = StudentModelSerializer

    # 在使用GenericAPIView視圖獲取或操做單個數據時,視圖方法中的表明主鍵的參數最好是pk
    def get(self,request,pk):
        """獲取一條數據"""
        return self.retrieve(request,pk)

    def put(self,request,pk):
        """更新一條數據"""
        return self.update(request,pk)

    def delete(self,request,pk):
        """刪除一條數據"""
        return self.destroy(request,pk)

9.2.3 GenericAPIView的視圖子類

1)CreateAPIView

提供 post 方法

繼承自: GenericAPIView、CreateModelMixin

2)ListAPIView

提供 get 方法

繼承自:GenericAPIView、ListModelMixin

3)RetrieveAPIView

提供 get 方法

繼承自: GenericAPIView、RetrieveModelMixin

4)DestoryAPIView

提供 delete 方法

繼承自:GenericAPIView、DestoryModelMixin

5)UpdateAPIView

提供 put 和 patch 方法

繼承自:GenericAPIView、UpdateModelMixin

6)RetrieveUpdateAPIView

提供 get、put、patch方法

繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestoryAPIView

提供 get、put、patch、delete方法

繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

9.3 視圖集ViewSet

使用視圖集ViewSet,能夠將一系列邏輯相關的動做放到一個類中:

  • list() 提供一組數據
  • retrieve() 提供單個數據
  • create() 建立數據
  • update() 保存數據
  • destory() 刪除數據

ViewSet視圖集類再也不實現get()、post()等方法,而是實現動做 action 如 list() 、create() 等。

視圖集只在使用as_view()方法的時候,纔會將action動做與具體請求方式對應上。如:

class BookInfoViewSet(viewsets.ViewSet):

    def list(self, request):
        books = BookInfo.objects.all()
        serializer = BookInfoSerializer(books, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        try:
            books = BookInfo.objects.get(id=pk)
        except BookInfo.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = BookInfoSerializer(books)
        return Response(serializer.data)

在設置路由時,咱們能夠以下操做

urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]

9.3.1 經常使用視圖集父類

1) ViewSet

繼承自APIViewViewSetMixin,做用也與APIView基本相似,提供了身份認證、權限校驗、流量管理等。

ViewSet主要經過繼承ViewSetMixin來實如今調用as_view()時傳入字典(如{'get':'list'})的映射處理工做。

在ViewSet中,沒有提供任何動做action方法,須要咱們本身實現action方法。

2)GenericViewSet

使用ViewSet一般並不方便,由於list、retrieve、create、update、destory等方法都須要本身編寫,而這些方法與前面講過的Mixin擴展類提供的方法同名,因此咱們能夠經過繼承Mixin擴展類來複用這些方法而無需本身編寫。可是Mixin擴展類依賴與GenericAPIView,因此還須要繼承GenericAPIView

GenericViewSet就幫助咱們完成了這樣的繼承工做,繼承自GenericAPIViewViewSetMixin,在實現了調用as_view()時傳入字典(如{'get':'list'})的映射處理工做的同時,還提供了GenericAPIView提供的基礎方法,能夠直接搭配Mixin擴展類使用。

舉例:

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

url的定義

urlpatterns = [
    path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
    re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),

]

3)ModelViewSet

繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4)ReadOnlyModelViewSet

繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin。

9.3.2 視圖集中定義附加action動做

在視圖集中,除了上述默認的方法動做外,還能夠添加自定義動做。

舉例:

from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def login(self,request):
        """學生登陸功能"""
        return Response({"message":"登陸成功"})

url的定義

urlpatterns = [
    path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
    re_path("students8/(?P<pk>\d+)/",
            views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),

    path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"}))

]

9.3.3 action屬性

在視圖集中,咱們能夠經過action對象屬性來獲取當前請求視圖集時的action動做是哪一個。

例如:

from rest_framework.viewsets import ModelViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get_new_5(self,request):
        """獲取最近添加的5個學生信息"""
        # 操做數據庫
        print(self.action) # 獲取本次請求的視圖方法名
        
        
經過路由訪問到當前方法中.能夠看到本次的action就是請求的方法名

10. 路由Routers

對於視圖集ViewSet,咱們除了能夠本身手動指明請求方式與動做action之間的對應關係外,還可使用Routers來幫助咱們快速實現路由信息。

REST framework提供了兩個router

  • SimpleRouter
  • DefaultRouter

10.1 使用方法

1) 建立router對象,並註冊視圖集,例如

from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'router_stu', StudentModelViewSet, base_name='student')

register(prefix, viewset, base_name)

  • prefix 該視圖集的路由前綴
  • viewset 視圖集
  • base_name 路由別名的前綴

如上述代碼會造成的路由以下:

^books/$    name: book-list
^books/{pk}/$   name: book-detail

2)添加路由數據

能夠有兩種方式:

urlpatterns = [
    ...
]
urlpatterns += router.urls

urlpatterns = [
    ...
    url(r'^', include(router.urls))
]

使用路由類給視圖集生成了路由地址

from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def login(self,request):
        """學生登陸功能"""
        print(self.action)
        return Response({"message":"登陸成功"})

路由代碼:

from django.urls import path, re_path
from . import views
urlpatterns = [
    ...
]

"""使用drf提供路由類router給視圖集生成路由列表"""
# 實例化路由類
# drf提供一共提供了兩個路由類給咱們使用,他們用法一致,功能幾乎同樣
from rest_framework.routers import DefaultRouter
router = DefaultRouter()

# 註冊視圖集
# router.register("路由前綴",視圖集類)
router.register("router_stu",views.StudentModelViewSet)

# 把生成的路由列表追加到urlpatterns
print( router.urls )
urlpatterns += router.urls

上面的代碼就成功生成了路由地址[增/刪/改/查一條/查多條的功能],可是不會自動咱們在視圖集自定義方法的路由。

因此咱們若是也要給自定義方法生成路由,則須要進行action動做的聲明。

10.2 視圖集中附加action的聲明

在視圖集中,若是想要讓Router自動幫助咱們爲自定義的動做生成路由信息,須要使用rest_framework.decorators.action裝飾器。

以action裝飾器裝飾的方法名會做爲action動做名,與list、retrieve等同。

action裝飾器能夠接收兩個參數:

  • methods: 聲明該action對應的請求方式,列表傳遞

  • detail

    : 聲明該action的路徑是否與單一資源對應,及是不是

    xxx/<pk>/action方法名/
    • True 表示路徑格式是xxx/<pk>/action方法名/
    • False 表示路徑格式是xxx/action方法名/

舉例:

from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action

class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    # methods 設置當前方法容許哪些http請求訪問當前視圖方法
    # detail 設置當前視圖方法是不是操做一個數據
    # detail爲True,表示路徑名格式應該爲 router_stu/{pk}/login/
    @action(methods=['get'], detail=True)
    def login(self, request,pk):
        """登陸"""
        ...

    # detail爲False 表示路徑名格式應該爲 router_stu/get_new_5/
    @action(methods=['put'], detail=False)
    def get_new_5(self, request):
        """獲取最新添加的5個學生信息"""
        ...

由路由器自動爲此視圖集自定義action方法造成的路由會是以下內容:

^router_stu/get_new_5/$    name: router_stu-get_new_5
^router_stu/{pk}/login/$   name: router_stu-login

10.3 路由router造成URL的方式

1) SimpleRouter

SimpleRouter

2)DefaultRouter

DefaultRouter

DefaultRouter與SimpleRouter的區別是,DefaultRouter會多附帶一個默認的API根視圖,返回一個包含全部列表視圖的超連接響應數據。

11. 認證Authentication

能夠在配置文件中配置全局默認的認證方案

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',  # session認證
        'rest_framework.authentication.BasicAuthentication',   # 基本認證
    )
}

也能夠在每一個視圖中經過設置authentication_classess屬性來設置

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # 類屬性
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    ...

認證失敗會有兩種可能的返回值:

  • 401 Unauthorized 未認證
  • 403 Permission Denied 權限被禁止

12. 權限Permissions

權限控制能夠限制用戶對於視圖的訪問和對於具體數據對象的訪問。

  • 在執行視圖的dispatch()方法前,會先進行視圖訪問權限的判斷
  • 在經過get_object()獲取具體對象時,會進行模型對象訪問權限的判斷

12.1使用

能夠在配置文件中全局設置默認的權限管理類,如

REST_FRAMEWORK = {
    ....
    
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

若是未指明,則採用以下默認配置

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

也能夠在具體的視圖中經過permission_classes屬性來設置,如

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)
    ...

12.2提供的權限

  • AllowAny 容許全部用戶
  • IsAuthenticated 僅經過認證的用戶
  • IsAdminUser 僅管理員用戶
  • IsAuthenticatedOrReadOnly 已經登錄認證的用戶能夠對數據進行增刪改操做,沒有登錄認證的只能查看數據。

舉例

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]

12.3自定義權限

如需自定義權限,需繼承rest_framework.permissions.BasePermission父類,並實現如下兩個任何一個方法或所有

  • .has_permission(self, request, view)

    是否能夠訪問視圖, view表示當前視圖對象

  • .has_object_permission(self, request, view, obj)

    是否能夠訪問數據對象, view表示當前視圖, obj爲數據對象

例如:

在當前子應用下,建立一個權限文件permissions.py中聲明自定義權限類:

from rest_framework.permissions import BasePermission

class IsXiaoMingPermission(BasePermission):
    def has_permission(self, request, view):
        if( request.user.username == "xiaoming" ):
            return True
from .permissions import IsXiaoMingPermission
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [IsXiaoMingPermission]

13. 限流Throttling

能夠對接口訪問的頻次進行限制,以減輕服務器壓力。

通常用於付費購買次數,投票等場景使用.

13.1使用

能夠在配置文件中,使用DEFAULT_THROTTLE_CLASSESDEFAULT_THROTTLE_RATES進行全局配置,

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}

DEFAULT_THROTTLE_RATES 可使用 second, minute, hourday來指明週期。

也能夠在具體視圖中經過throttle_classess屬性來配置,如

from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = (UserRateThrottle,)
    ...

13.1.1可選限流類

1) AnonRateThrottle

限制全部匿名未認證用戶,使用IP區分用戶。

使用DEFAULT_THROTTLE_RATES['anon'] 來設置頻次

2)UserRateThrottle

限制認證用戶,使用User id 來區分。

使用DEFAULT_THROTTLE_RATES['user'] 來設置頻次

3)ScopedRateThrottle

限制用戶對於每一個視圖的訪問頻次,使用ip或user id。

例如:

class ContactListView(APIView):
    throttle_scope = 'contacts'
    ...

class ContactDetailView(APIView):
    throttle_scope = 'contacts'
    ...

class UploadView(APIView):
    throttle_scope = 'uploads'
    ...
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}

13.2實例

全局配置中設置訪問頻率

'DEFAULT_THROTTLE_RATES': {
        'anon': '3/minute',
        'user': '10/minute'
    }
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)

14. 過濾Filtering

對於列表數據可能須要根據字段進行過濾,咱們能夠經過添加django-fitlter擴展來加強支持。

pip install django-filter

在配置文件中增長過濾後端的設置:

INSTALLED_APPS = [
    ...
    'django_filters',  # 須要註冊應用,
]

REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

在視圖中添加filter_fields屬性,指定能夠過濾的字段

class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    filter_fields = ('age', 'sex')

# 127.0.0.1:8000/four/students/?sex=1

15. 排序

對於列表數據,REST framework提供了OrderingFilter過濾器來幫助咱們快速指明數據按照指定字段進行排序。

使用方法:

在類視圖中設置filter_backends,使用rest_framework.filters.OrderingFilter過濾器,REST framework會在請求的查詢字符串參數中檢查是否包含了ordering參數,若是包含了ordering參數,則按照ordering參數指明的排序字段對數據集進行排序。

前端能夠傳遞的ordering參數的可選字段值須要在ordering_fields中指明。

示例:

class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'age')

# 127.0.0.1:8000/books/?ordering=-age
# -id 表示針對id字段進行倒序排序
# id  表示針對id字段進行升序排序

若是須要在過濾之後再次進行排序,則須要二者結合!

from rest_framework.generics import ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
class Student3ListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_fields = ('age', 'sex')
    # 由於局部配置會覆蓋全局配置,因此須要從新把過濾組件核心類再次聲明,
    # 不然過濾功能會失效
    filter_backends = [OrderingFilter,DjangoFilterBackend]
    ordering_fields = ('id', 'age')

16. 分頁Pagination

REST framework提供了分頁的支持。

咱們能夠在配置文件中設置全局的分頁方式,如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100  # 每頁數目
}

也可經過自定義Pagination類,來爲視圖添加不一樣分頁行爲。在視圖中經過pagination_clas屬性來指明。

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000
    page_size_query_param = 'page_size'
    max_page_size = 10000
class BookDetailView(RetrieveAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    pagination_class = LargeResultsSetPagination

注意:若是在視圖內關閉分頁功能,只需在視圖內設置

pagination_class = None

16.1可選分頁器

1) PageNumberPagination

前端訪問網址形式:

GET  http://127.0.0.1:8000/students/?page=4

能夠在子類中定義的屬性:

  • page_size 每頁數目
  • page_query_param 前端發送的頁數關鍵字名,默認爲"page"
  • page_size_query_param 前端發送的每頁數目關鍵字名,默認爲None
  • max_page_size 前端最多能設置的每頁數量
# 聲明分頁的配置類
from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
    # 默認每一頁顯示的數據量
    page_size = 2
    # 容許客戶端經過get參數來控制每一頁的數據量
    page_size_query_param = "size"
    max_page_size = 10
    # 自定義頁碼的參數名
    page_query_param = "p"

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    pagination_class = StandardPageNumberPagination

# 127.0.0.1/four/students/?p=1&size=5

2)LimitOffsetPagination

前端訪問網址形式:

GET http://127.0.0.1/four/students/?limit=100&offset=400

能夠在子類中定義的屬性:

  • default_limit 默認限制,默認值與PAGE_SIZE設置一直
  • limit_query_param limit參數名,默認'limit'
  • offset_query_param offset參數名,默認'offset'
  • max_limit 最大limit限制,默認None
from rest_framework.pagination import LimitOffsetPagination
class StandardLimitOffsetPagination(LimitOffsetPagination):
    # 默認每一頁查詢的數據量,相似上面的page_size
    default_limit = 2
    limit_query_param = "size"
    offset_query_param = "start"

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 調用頁碼分頁類
    # pagination_class = StandardPageNumberPagination
    # 調用查詢偏移分頁類
    pagination_class = StandardLimitOffsetPagination

17. 異常處理 Exceptions

REST framework提供了異常處理,咱們能夠自定義異常處理函數。

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
    # 先調用REST framework默認的異常處理方法得到標準錯誤響應對象
    response = exception_handler(exc, context)

    # 在此處補充自定義的異常處理
    if response is None:
        response.data['status_code'] = response.status_code

    return response

在配置文件中聲明自定義的異常處理

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}

若是未聲明,會採用默認的方式,以下

rest_frame/settings.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

例如:

補充上處理關於數據庫的異常

from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError

def exception_handler(exc, context):
    response = drf_exception_handler(exc, context)

    if response is None:
        view = context['view']
        if isinstance(exc, DatabaseError):
            print('[%s]: %s' % (view, exc))
            response = Response({'detail': '服務器內部錯誤'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

    return response

17.1REST framework定義的異常

  • APIException 全部異常的父類
  • ParseError 解析錯誤
  • AuthenticationFailed 認證失敗
  • NotAuthenticated 還沒有認證
  • PermissionDenied 權限決絕
  • NotFound 未找到
  • MethodNotAllowed 請求方式不支持
  • NotAcceptable 要獲取的數據格式不支持
  • Throttled 超過限流次數
  • ValidationError 校驗失敗

也就是說,不少的沒有在上面列出來的異常,就須要咱們在自定義異常中本身處理了。

18. 自動生成接口文檔

REST framework能夠自動幫助咱們生成接口文檔。

接口文檔以網頁的方式呈現。

自動接口文檔能生成的是繼承自APIView及其子類的視圖。

18.1. 安裝依賴

REST framewrok生成接口文檔須要coreapi庫的支持。

pip install coreapi

18.2. 設置接口文檔訪問路徑

在總路由中添加接口文檔路徑。

文檔路由對應的視圖配置爲rest_framework.documentation.include_docs_urls

參數title爲接口文檔網站的標題。

from rest_framework.documentation import include_docs_urls

urlpatterns = [
    ...
    path('docs/', include_docs_urls(title='站點頁面標題'))
]

18.3. 文檔描述說明的定義位置

1) 單一方法的視圖,可直接使用類視圖的文檔字符串,如

class BookListView(generics.ListAPIView):
    """
    返回全部圖書信息.
    """

2)包含多個方法的視圖,在類視圖的文檔字符串中,分開方法定義,如

class BookListCreateView(generics.ListCreateAPIView):
    """
    get:
    返回全部圖書信息.

    post:
    新建圖書.
    """

3)對於視圖集ViewSet,仍在類視圖的文檔字符串中封開定義,可是應使用action名稱區分,如

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    """
    list:
    返回圖書列表數據

    retrieve:
    返回圖書詳情數據

    latest:
    返回最新的圖書數據

    read:
    修改圖書的閱讀量
    """

18.4. 訪問接口文檔網頁

瀏覽器訪問 127.0.0.1:8000/docs/,便可看到自動生成的接口文檔。

接口文档网页

兩點說明:

1) 視圖集ViewSet中的retrieve名稱,在接口文檔網站中叫作read

2)參數的Description須要在模型類或序列化器類的字段中以help_text選項定義,如:

class Student(models.Model):
    ...
    age = models.IntegerField(default=0, verbose_name='年齡', help_text='年齡')
    ...

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
            'age': {
                'required': True,
                'help_text': '年齡'
            }
        }

19. Xadmin

xadmin是Django的第三方擴展,比使用Django的admin站點更強大也更方便。

文檔:https://xadmin.readthedocs.io/en/latest/index.html

19.1. 安裝

經過以下命令安裝xadmin的最新版

pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2

在配置文件中註冊以下應用

INSTALLED_APPS = [
    ...
    'xadmin',
    'crispy_forms',
    'reversion',
    ...
]

# 修改使用中文界面
LANGUAGE_CODE = 'zh-Hans'

# 修改時區
TIME_ZONE = 'Asia/Shanghai'

xadmin有創建本身的數據庫模型類,須要進行數據庫遷移

python manage.py makemigrations
python manage.py migrate

在總路由中添加xadmin的路由信息

import xadmin
xadmin.autodiscover()

# version模塊自動註冊須要版本控制的 Model
from xadmin.plugins import xversion
xversion.register_models()

urlpatterns = [
    path(r'xadmin/', xadmin.site.urls),
]

若是以前沒有建立超級用戶,須要建立,若是有了,則能夠直接使用以前的。

python manage.py createsuperuser

19.2. 使用

  • xadmin再也不使用Django的admin.py,而是須要編寫代碼在adminx.py文件中。
  • xadmin的站點管理類不用繼承admin.ModelAdmin,而是直接繼承object便可。

例如:在子應用中建立adminx.py文件。

站點的全局配置

import xadmin
from xadmin import views

class BaseSetting(object):
    """xadmin的基本配置"""
    enable_themes = True  # 開啓主題切換功能
    use_bootswatch = True

xadmin.site.register(views.BaseAdminView, BaseSetting)

class GlobalSettings(object):
    """xadmin的全局配置"""
    site_title = "路飛學城"  # 設置站點標題
    site_footer = "路飛學城有限公司"  # 設置站點的頁腳
    menu_style = "accordion"  # 設置菜單摺疊

xadmin.site.register(views.CommAdminView, GlobalSettings)

站點Model管理

xadmin可使用的頁面樣式控制基本與Django原生的admin一直。

  • list_display 控制列表展現的字段

    list_display = ['id', 'btitle', 'bread', 'bcomment']
  • search_fields 控制能夠經過搜索框搜索的字段名稱,xadmin使用的是模糊查詢

    search_fields = ['id','btitle']
  • list_filter 能夠進行過濾操做的列,對於分類、性別、狀態

    list_filter = ['is_delete']
  • ordering 默認排序的字段

  • show_detail_fields 在列表頁提供快速顯示詳情信息

  • list_editable 在列表頁能夠快速直接編輯的字段

  • refresh_times 指定列表頁的定時刷新

    refresh_times = [5, 10,30,60]  # 設置容許後端管理人員按多長時間(秒)刷新頁面
  • list_export 控制列表頁導出數據的可選格式

    list_export = ('xls', 'xml', 'json')   list_export設置爲None來禁用數據導出功能
    list_export_fields = ('id', 'btitle', 'bpub_date')
  • show_bookmarks 控制是否顯示書籤功能

    show_bookmarks = True
  • data_charts 控制顯示圖表的樣式

    data_charts = {
            "order_amount": {
              'title': '圖書發佈日期表', 
              "x-field": "bpub_date", 
              "y-field": ('btitle',),
              "order": ('id',)
            },
        #    支持生成多個不一樣的圖表
        #    "order_amount": {
        #      'title': '圖書發佈日期表', 
        #      "x-field": "bpub_date", 
        #      "y-field": ('btitle',),
        #      "order": ('id',)
        #    },
        }
    • title 控制圖標名稱
    • x-field 控制x軸字段
    • y-field 控制y軸字段,能夠是多個值
    • order 控制默認排序
  • model_icon 控制菜單的圖標【圖標的設置能夠參考bootstrap的圖標css名稱】

    class BookInfoAdmin(object):
        model_icon = 'fa fa-gift'
    
    xadmin.site.register(models.BookInfo, BookInfodmin)
  • readonly_fields 在編輯頁面的只讀字段

  • exclude 在編輯頁面隱藏的字段

相關文章
相關標籤/搜索