原文: www.valentinog.com/blog/tutori…html
翻譯版實踐教程: Django Rest 與 React(Django2.1 加 一點小測試 加一點譯者的小額外功能)前端
最終構建了一個有後臺管理 + 提供api服務 + Mysql數據庫 + 在線api文檔的Lead系統。python
一個實用(自認爲)的介紹: 實用Django REST 與 React,特性! Django2.1!mysql
現在(可供開發選擇的)web框並不匱乏。react
想要構建一個API服務? 這裏列舉出一些你能夠立馬想到說出名字的: Laravel, Rails, Node.js and Koa 2, Phoenix。webpack
可是擺在咱們面前的現實是: 客戶想要一個儘量快的原型,這時我該如何作?git
我選擇了一個web 框架,他:github
請信我! 當涉及到開發速度時,Django是很好的一個選擇。 可是如何去建立一個簡單的Django Rest API呢?如何去 組織構建 一個Django 項目 與 React呢?web
不要懼怕,咱們將在下面的教程中一塊兒探索。sql
在下面的教程中你將會學到:
咱們將要作個啥嘞? 在這個項目裏,咱們將會構建一個簡單的 API 來列出並存儲領導。
爲了能繼續跟進下面的教程,你應該擁有:
準備好了?讓咱們一塊兒出發吧!
首要的是來確認你擁有一個虛擬的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項目包含許多的 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啓動的虛擬環境下執行的。
你將看到一個新的名字爲leads的文件夾,在你的/YOUR_CODE_DIR/django-drf-react-quickstart/目錄中。
就像上圖這樣。
如今讓咱們告訴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
]
複製代碼
到目前爲止一切順利。
# 起手式
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連環般麻煩。
# 第一全,文件全添加
git add .
# 第二全,commit信息要全
git commit -m "巴啦啦小魔仙balala"
# 第三全,全網速推上雲
git push
複製代碼
注意: 在進行下一步以前,請確保你仍然位於: /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時,請盡力選擇對於你的案例最適合的那些字段。
pipenv install mysqlclient
複製代碼
新建一個mysql數據庫
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中生成的表:
很是棒, 下一小節咱們將討論序列化器和試圖,可是首先咱們須要一點小小的測試。
此時此刻,你或許在驚歎"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的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
注意: 開始下面以前,請確保你仍然在/YOUR_CODE_DIR/django-drf-react-quickstart/
目錄。
什麼是序列化? 什麼是Django REST 序列器?
序列化是轉換一個對象到另外一種數據格式的一種動做。在對象轉換完成後,咱們能夠將它保存到文件,或者在互聯網中發送它。
爲何序列化如此必要呢?
思考一個Django model: 它是一個Python的嘞, 你該如何在瀏覽器中渲染一個Python的類到JSON 呢?
使用Django REST 序列器!
一個序列器 也能夠反向工做: 它轉換 JSON 到 對象
這種方式你能夠:
簡要歸納: 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。
注意: 開始下面以前,請確保你仍然在/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 框架中,有不少方法能夠編寫視圖:
在這個教程的範圍內,我將使用 generic API view,目的是爲了寫更少的代碼。
咱們的簡單app應該有:
經過閱讀generic API views documentation 咱們能夠看到一件提供給咱們一個能夠用於列出和建立models的view。
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 到 視圖
咋整? 敬請期待下一節
注意: 開始下面以前,請確保你仍然在/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
此時你能夠經過網頁上內建的表單來建立一些數據
在下一節中,咱們將學習如何在Django 中餵養數據庫(-v-)
注意: 開始下面以前,請確保你仍然在/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
複製代碼
這就是所有了,下面的部分,咱們將實現一個簡單的React 前端!
pipenv install https://codeload.github.com/sshwsfc/xadmin/zip/django2
複製代碼
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
]
複製代碼
from django.urls import path, include
import xadmin
urlpatterns = [
path('', include('leads.urls')),
path('xadmin/', xadmin.site.urls),
]
複製代碼
添加了xadmin的import 和 xadmin path url mapping。
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/
pipenv install coreapi
複製代碼
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
]
複製代碼
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
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/
大功告成: 咱們有了一個既有後臺,又提供api,又有在線API文檔的Lead服務啦。
敬請期待下次更新React篇! 敬請期待下次更新React篇! 敬請期待下次更新React篇!