Django Rest 與 React(Django2.1 + coverage測試 + xadmin + 線上api文件)-翻譯實踐強化版

天涯明月笙發表於2019-01-07

原文: www.valentinog.com/blog/tutori…

翻譯版實踐教程: Django Rest 與 React(Django2.1 加 一點小測試 加一點譯者的小額外功能)

最終構建了一個有後臺管理 + 提供api服務 + Mysql資料庫 + 線上api文件的Lead系統。

一個實用(自認為)的介紹: 實用Django REST 與 React,特性! Django2.1!

mark

如今(可供開發選擇的)web框並不匱乏。

想要構建一個API服務? 這裡列舉出一些你可以立馬想到說出名字的: Laravel, Rails, Node.js and Koa 2, Phoenix。

但是擺在我們面前的現實是: 客戶想要一個儘可能快的原型,這時我該如何做?

我選擇了一個web 框架,他:

  • 讓我可以寫更少的程式碼
  • 讓我可以儘可能遵循MVP模式
  • 為擴充套件專案提供了一個穩定的基礎

請信我! 當涉及到開發速度時,Django是很好的一個選擇。 但是如何去建立一個簡單的Django Rest API呢?如何去 組織構建 一個Django 專案 與 React呢?

不要害怕,我們將在下面的教程中一起探索。

目錄

  • Django REST with React: 我們將會學到什麼
  • Django REST with React: requirements(環境依賴)
  • Django REST with React: 為專案建立一個虛擬的 Python 環境
  • Django REST with React: 構建一個 Django 的 application
  • Django REST with React: 建立一個 Django Model(譯者增 GitHub 託管程式碼)
  • Django REST with React: 一丟丟測試
  • Django REST with React: Django Rest serializers(序列化器)
  • Django REST with React: 設定檢視控制器
  • Django REST with React: 設定urls 路由
  • Django REST with React: (seeding)餵養資料庫
  • Django REST with React: Django 與 React 協同
  • Django REST with React: 構建 React 與 webpack
  • Django REST with React: React 前端
  • Django REST with React: 前端測試
  • Django REST with React: 構建一個React 表單
  • Django REST with React: 總結
  • Django REST with React: 資源

Django REST with React: 我們將會學到什麼

在下面的教程中你將會學到:

  • 如何構建一個簡單的 Django REST API
  • 如何組織構建一個 Django project 與 React

我們將要做個啥嘞? 在這個專案裡,我們將會構建一個簡單的 API 來列出並儲存領導。

Django REST with React: requirements(環境依賴)

為了能繼續跟進下面的教程,你應該擁有:

  • 掌握 Python 與 Django 基礎
  • 掌握 JavaScript ES6 和 React 基礎
  • 在你的電腦系統中安裝一個新版本的 Node.js

準備好了?讓我們一起出發吧!

Django REST with React: 為專案建立一個虛擬的Python環境

首要的是來確認你擁有一個虛擬的Python環境,你可以在Python3中使用 pipenv,pyenv,或者venv模組。 (譯者推薦使用pipenv)

pip install pipenv
mkdir django-drf-react-quickstart && cd django-drf-react-quickstart
pipenv shell
複製程式碼

然後安裝依賴: 安裝Django 和 Django REST framework 通過下面命令:

pipenv install django djangorestframework
複製程式碼

當安裝結束,你可以通過下面命令建立一個新的Django 專案:

django-admin startproject drf_react .
複製程式碼

現在我們可以開始構建我們的第一個Django app 來 列出與儲存leads

Django REST with React: 構建一個Django的application

一個Django專案包含許多的 applications(應用)。理想狀態下 每個應用應該只做一件事。

Django applications(應用) 是模組化的,可重用的。 例如: 我建立了一個lead 應用用來建立和列出領導。

如果其他專案需要一個相同的app,我可以通過 package manager(INSTALLED_APPS) 來安裝leads。嗯,沒錯,這就是全部。

我建議去閱讀 How to write reusable apps,並觀看 DjangoCon 2008: Reusable Apps 來學習關於app的最佳實踐。

在Django中建立一個新的application,你應該執行:

django-admin startapp app_name 
複製程式碼

為了在專案的資料夾中建立leads app:

cd django-drf-react-quickstart
複製程式碼

然後初始化我們的app:

django-admin startapp leads
複製程式碼

注意: 我需要假設你位於 /YOUR_CODE_DIR/django-drf-react-quickstart/來執行的上述命令! 以及這些命令是在pipenv shell啟動的虛擬環境下執行的。

mark

你將看到一個新的名字為leads的資料夾,在你的/YOUR_CODE_DIR/django-drf-react-quickstart/目錄中。

mark

就像上圖這樣。

現在讓我們告訴Django如何使用這個新的app

開啟 ./drf_react/settings.py 並新增這個app在 INSTALLED_APPS中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'leads', # 新增leads app
]
複製程式碼

到目前為止一切順利。

譯者附加教程(GitHub管理程式碼)

  • GitHub 新建Repo

mark

  • GitHub 奪命N連環
# 起手式
git init
# 新增當前檔案進入式
git add .
# commit檔案式
git commit -m "初始化專案目錄,新增leads app"
# 設定要上哪個雲端式
git remote add origin https://github.com/mtianyan/django-drf-react-quickstart.git
# 把網頁新建拉下來式
git pull --rebase origin master
# push真的上雲式
git push --set-upstream origin master
複製程式碼

首次使用才如上面N連環般麻煩。

  • GitHub 奪命三全
# 第一全,檔案全新增
git add .
# 第二全,commit資訊要全
git commit -m "巴啦啦小魔仙balala"
# 第三全,全網速推上雲
git push 
複製程式碼

Django REST with React: 建立一個Django Model

注意: 在進行下一步之前,請確保你仍然位於: /YOUR_CODE_DIR/django-drf-react-quickstart/

隨著app的安裝,我們是時候來建立我們的第一個model了,一個model 是一個物件用來表示你的表資料。幾乎每個web 框架都擁有models這個概念。 Django 也不例外。

一個Django模型可以擁有一個或多個欄位: 每個欄位是你資料表中的一列,當進行下一步之前,讓我們為我們的lead app 定義它的依賴。

首先我們需要一個 Lead model

由於我收集了leads的資訊,我認為一個Lead model 應該擁有以下欄位:

  • 一個名字
  • 一個郵件
  • 一個資訊

(感覺新增額外的欄位也很輕鬆,例如我們想再加個手機號)

請不要忘記一個 時間戳 欄位! Django 不會預設的為你新增一個 created_at 列。

很好!

開啟 ./leads/models.py然後建立Lead model:

from django.db import models
class Lead(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    message = models.CharField(max_length=300)
    created_at = models.DateTimeField(auto_now_add=True)
複製程式碼

這裡有一個關於models的快速指南: 花時間看看 -> Django fields documentation

當計劃一個model時,請盡力選擇對於你的案例最適合的那些欄位。

(譯者)附加使用mysql及本地化時間等

pipenv install mysqlclient
複製程式碼

新建一個mysql資料庫

mark

settings -> 修改為使用mysql資料庫:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'drf_react',
        'USER': 'root',
        'PASSWORD': '密碼',
        'HOST':'127.0.0.1'

    }
}
複製程式碼

settings -> 設定本地化

# 語言改為中文
LANGUAGE_CODE = 'zh-hans'

# 時區改為上海
TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

# 資料庫儲存使用時間,True時間會被存為UTC的時間
USE_TZ = False
複製程式碼

在model定義就位之後,讓我們一起建立一個migration(遷移) 通過執行:

python manage.py makemigrations leads
複製程式碼

並最終 migrate 到資料庫使用下面命令:

python manage.py migrate
複製程式碼

可以看到mysql中生成的表:

mark

非常棒, 下一小節我們將討論序列化器和試圖,但是首先我們需要一點小小的測試。

Django REST with React: 一丟丟測試

此時此刻,你或許在驚歎"Valentino(作者名), 咋測試這個app"

不會讓TDD(測試驅動開發) 教程來把你搞崩潰,我將給你一些小技巧(tips)

我見過大量的Django 教程裡都是這樣開始寫的:

class SomeModelModelTest(TestCase):
    def setUp(self):
        SomeModel.objects.create(
            name=fake.name(),
            email=fake.email(),
            phone=fake.phone_number(),
            message=fake.text(),
            source=fake.url()
        )
    def test_save_model(self):
        saved_models = SomeModel.objects.count()
        self.assertEqual(saved_models, 2)
複製程式碼

不要這樣做,這對於測試Django model 或 Django ORM 都是沒踩對點的(沒啥用的)。

對於Django裡的測試,這裡有一個好的出發點:

  • 不要測試 Django 的內建程式碼(models views 等)
  • 不要測試 Python 的內建函式

總的來說: 不要測試那些已經被測試過的!

那我該測些啥呢? 你是否在Django的model中新增了一個 custom method(自定義的方法)? 測它!

你是否有一個custom view(自定義的檢視)呢? 測它! 但是我怎麼知道要去測試啥呢?

通過安裝工具 coverage 來幫自己一點忙

pipenv install coverage
複製程式碼

然後,每當你新增一些程式碼到你的應用時,執行coverage:

coverage run --source='.' manage.py test
複製程式碼

然後會產生報告:

coverage html
複製程式碼

用瀏覽器開啟 /YOUR_CODE_DIR/django-drf-react-quickstart/htmlcov/index.html,你將看到你需要測試啥。

如果你更想在命令列裡看到測試報告,你可以執行:

coverage report
複製程式碼

等會! 你堅持看到了這? 我感動死了。

不要停! 緊緊抱住我的大腿, 下一節我們將看看序列化器(serializers)!

breakpoint: 奪命三全 -> push

Django REST with React: Django Rest serializers(序列化器)

注意: 開始下面之前,請確保你仍然在/YOUR_CODE_DIR/django-drf-react-quickstart/ 目錄。

什麼是序列化? 什麼是Django REST 序列器

序列化是轉換一個物件到另一種資料格式的一種動作。在物件轉換完成後,我們可以將它儲存到檔案,或者在網際網路中傳送它。

為什麼序列化如此必要呢?

思考一個Django model: 它是一個Python的嘞, 你該如何在瀏覽器中渲染一個Python的類到JSON 呢?

使用Django REST 序列器!

一個序列器 也可以反向工作: 它轉換 JSON 到 物件

這種方式你可以:

  • 通過轉換Django的models到JSON,來在瀏覽器中檢視它們。
  • 製作 一個JSON 負載的 CURD(增刪改查) 的請求到API

簡要概括: DjangoREST 序列器 是操作模型到API的主宰。

建立一個新檔案: ./leads/serializers.py. 這個LeadSerializer 接收我們的Lead model 與一些欄位

from rest_framework import serializers
from leads.models import Lead
class LeadSerializer(serializers.ModelSerializer):
    class Meta:
        model = Lead
        fields = ('id', 'name', 'email', 'message')
複製程式碼

就像上面你能看到的程式碼裡那樣,我們繼承了ModelSerializer。

一個 ModelSerializer 在Django REST中就像一個 ModelForm

它非常適合於,任何你想接近 對映一個Model 到 一個Serializer 中時。

除了明確的定義需要對映的欄位,你也可以對映model中的所有欄位。

from rest_framework import serializers
from leads.models import Lead
class LeadSerializer(serializers.ModelSerializer):
    class Meta:
        model = Lead
        fields = '__all__'
複製程式碼

儲存並關閉檔案,我們離完成app更近了一步。

下面的章節裡,我們將看一下 views(檢視) 和 urls。

Django REST with React: 設定檢視控制器

注意: 開始下面之前,請確保你仍然在/YOUR_CODE_DIR/django-drf-react-quickstart/ 目錄。

如果你從其他框架轉到Django,你可能感到驚奇的是: Django 沒有控制器!

控制器用來封裝處理 request 請求的邏輯並返回response。傳統的MVC 體系 包含 Model(模型), View(檢視), Controller(控制器)

這樣的MVC框架有: Rails, Phoenix, Laravel。

Django 是一個 MVT framework,它有的三層是: Model(模型) - View (檢視) - Template(模板)。其中View(檢視) 關注著請求和響應的一整個生命週期。

Django中很多型別的views: function views 函式檢視, class based views 基於類的檢視, and generic views 通用檢視.

雖然很多開發者相對於class based views(基於類的檢視)更喜歡 function views (函式檢視),但我是後者(基於類)的一個大粉絲

當我選擇Django,因為我的核心價值要求是: 開發速度,DRY(dont repeat yourself),更少的程式碼。

當已經存在一組合理的預設值時,我認為繼續手寫Code是沒有意義的。

這是我的經驗法則:

僅當我們想要自定義通用檢視所花費的時間超過手動編寫檢視所花費的時間時,才使用函式檢視。

與簡單的Django一樣,在Django REST 框架中,有很多方法可以編寫檢視:

  • function based views(基於函式的檢視)
  • class based views(基於類的檢視)
  • generic API views(通用的API 檢視)

在這個教程的範圍內,我將使用 generic API view,目的是為了寫更少的程式碼。

我們的簡單app應該有:

  • 列出模型中的集合
  • 建立一個新的物件到資料庫中

通過閱讀generic API views documentation 我們可以看到一件提供給我們一個可以用於列出和建立models的view。

它就是 ListCreateAPIView

ListCreateAPIView 接收一個queryset 和 一個序列化類作為引數。

開啟 ./leads/views.py 建立檢視:

from leads.models import Lead
from leads.serializers import LeadSerializer
from rest_framework import generics
class LeadListCreate(generics.ListCreateAPIView):
    queryset = Lead.objects.all()
    serializer_class = LeadSerializer
複製程式碼

通過三行程式碼我們建立了一個可以處理GET 和 POST請求的view。

現在還缺點啥呢? URL 對映! 換句話說,我們需要對映URLs 到 檢視

咋整? 敬請期待下一節

Django REST with React: 設定urls 路由

注意: 開始下面之前,請確保你仍然在/YOUR_CODE_DIR/django-drf-react-quickstart/ 目錄。

來自Rails, Phoenix, or Laravel 的朋友們,你可能又感到驚訝了,Django竟然沒有路由配置。

雖然DRF 提出了 resourceful router 資源化的路由,但最簡單的對映URl到檢視的方式還是URL mapping

我們的目標是聯通 LeadListCreate 到 api/lead/

換句話講,我們想要製作一個GET 和 POST請求到api/lead/ 來 列出和建立models。

./drf_react/urls.py配置URL mapping 包含app(leads)中的urls

from django.urls import path, include
urlpatterns = [
    path('', include('leads.urls')),
]
複製程式碼

下一步是建立一個新的檔案: ./leads/urls.py:

from django.urls import path
from . import views
urlpatterns = [
    path('api/lead/', views.LeadListCreate.as_view() ),
]
複製程式碼

最後: 我們要讓 rest_framework 註冊進 INSTALLED_APPS。

開啟 ./drf_react/settings.py 然後新增app 進入INSTALLED_APPS。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'leads', 
    'rest_framework' # 加入 rest framework
]
複製程式碼

此時你應該可以通過健全性檢查:

python manage.py runserver
複製程式碼

訪問: http://127.0.0.1:8000/api/lead/ 你將會看到 browsable API 可瀏覽式api

mark

此時你可以通過網頁上內建的表單來建立一些資料

在下一節中,我們將學習如何在Django 中餵養資料庫(-v-)

Django REST with React: (seeding)餵養資料庫

注意: 開始下面之前,請確保你仍然在/YOUR_CODE_DIR/django-drf-react-quickstart/ 目錄。

你可以使用 Django fixtures 來填充資料庫。

當你想要給前端一些demo資料時,Fixtures時非常有用的。

建立一個新資料夾: ./leads/fixtures

然後建立一個新的檔案: ./leads/fixtures/leads.json 內容為下面的JSON:

[
    {
        "model": "leads.lead",
        "pk": 1,
        "fields": {
            "name": "mtianyan",
            "email": "1147727180@qq.com",
            "message": "I am a happy pythoner",
            "created_at": "2019-01-07 00:00:00"
        }
    },
    {
        "model": "leads.lead",
        "pk": 2,
        "fields": {
            "name": "Tom",
            "email": "tomsomething@gmail.com",
            "message": "I want to talk about a Python project",
            "created_at": "2018-01-14 00:00:00"
        }
    }
]
複製程式碼

儲存並關閉這個檔案,然後使用下面命令載入fixture:

python manage.py loaddata leads
複製程式碼

mark

這就是全部了,下面的部分,我們將實現一個簡單的React 前端!

譯者新增: xadmin 管理 & drf 線上文件

安裝

pipenv install https://codeload.github.com/sshwsfc/xadmin/zip/django2
複製程式碼

註冊進INSTALL_APP

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'leads',          # 新增leads app
    'rest_framework', # 新增rest framework
    'xadmin',         # 新增 xadmin
    'crispy_forms',   # 新增 xadmin
]
複製程式碼

配置URL(django-drf-react-quickstart\drf_react\urls.py):

from django.urls import path, include
import xadmin

urlpatterns = [
    path('', include('leads.urls')),
    path('xadmin/', xadmin.site.urls),
]
複製程式碼

新增了xadmin的import 和 xadmin path url mapping。

新建adminx.py(django-drf-react-quickstart\leads\adaminx.py)

import xadmin
from xadmin import views
from .models import Lead
class BaseSetting(object):
	"""xadmin的基礎資訊配置"""
	enable_themes = True  # 開啟主題功能
	use_bootswatch = True 

class GlobalSettings(object):
	"""xadmin通用資訊配置"""
	site_title = "Leads Xadmin"
	site_footer = "mtianyan@qq.com"

# 註冊設定資訊到View
xadmin.site.register(views.BaseAdminView, BaseSetting)
xadmin.site.register(views.CommAdminView, GlobalSettings)

class LeadAdmin(object):
	"""
	list_display: 後臺展示哪些欄位
	search_fields: 後臺可搜尋哪些欄位
	list_filter: 後臺過濾器可使用哪些欄位
	"""
	list_display = ['name', 'email','message']
	search_fields = ['name', 'email','message']
	list_filter = ['name', 'email','message','created_at']

xadmin.site.register(Lead, LeadAdmin)
複製程式碼

遷移資料庫:

python manage.py makemigrations
python manage.py migrate
複製程式碼

建立後臺管理員

python manage.py createsuperuser
複製程式碼

登入後臺

執行

python manage.py runserver
複製程式碼

訪問: http://127.0.0.1:8000/xadmin/

mark

線上api互動文件

  • 安裝需要的包:
pipenv install coreapi
複製程式碼
  • 配置url(django-drf-react-quickstart\drf_react\urls.py)
from django.urls import path, include
import xadmin
from rest_framework.documentation import include_docs_urls # new 

urlpatterns = [
    path('', include('leads.urls')),
    path('xadmin/', xadmin.site.urls),
    path('api/docs/', include_docs_urls(title='Lead 線上API文件')), # new
]
複製程式碼
  • 新增註釋以便線上文件生成

models.py

from django.db import models

# Create your models here.
class Lead(models.Model):
    name = models.CharField(max_length=100,verbose_name="lead名字", help_text="lead名字")
    email = models.EmailField(verbose_name="郵箱", help_text="郵箱")
    message = models.CharField(max_length=300, verbose_name="資訊", help_text="資訊")
    created_at = models.DateTimeField(auto_now_add=True,verbose_name="建立時間", help_text="建立時間")
複製程式碼

新增verbose_name用於xadmin,help_text用於drf

views.py

class LeadListCreate(generics.ListCreateAPIView):
	"""
    get:
    返回所有已存在的lead物件的列表

    post:
    建立一個新的lead例項
	"""
	queryset = Lead.objects.all()
	serializer_class = LeadSerializer
複製程式碼
  • 執行:
python manage.py runserver
複製程式碼

訪問: http://127.0.0.1:8000/api/docs/

mark

大功告成: 我們有了一個既有後臺,又提供api,又有線上API文件的Lead服務啦。

敬請期待下次更新React篇! 敬請期待下次更新React篇! 敬請期待下次更新React篇!

相關文章