手把手Django+Vue前后端分離入門教程
1.前言
眾所周知,Django對于網(wǎng)站快速開發(fā)非常友好,這得益于框架為我們做了很多事情,讓我們只需要做一些簡單的配置和邏輯即可把網(wǎng)站的功能開發(fā)出來。
但是,在使用Django的過程中,有一個地方一直是比較難受的,那就是使用Django自帶的模版,這種通常需要自己利用HTML+CSS+Jquery的方式總感覺是上一個時代的做法,前后端分離無論對于開發(fā)效率、多端支持等等都是很有好處的。
所以,本文希望通過一個簡單的demo,講一講基于Django+Vue的前后端分離開發(fā),將Django作為一個純后端的服務,為前端Vue頁面提供數(shù)據(jù)支持。
本文采用的django版本號2.2.5,Vue版本2.9.6。
如果看不完可以先收藏關(guān)注哈~
開始之前,你要確保Python和pip已經(jīng)成功安裝在電腦上,如果沒有,可以訪問這篇文章:超詳細Python安裝指南?進行安裝。
(可選1)?如果你用Python的目的是數(shù)據(jù)分析,可以直接安裝Anaconda:Python數(shù)據(jù)分析與挖掘好幫手—Anaconda,它內(nèi)置了Python和pip.
(可選2)?此外,推薦大家用VSCode編輯器,它有許多的優(yōu)點:Python 編程的最好搭檔—VSCode 詳細指南。
請選擇以下任一種方式輸入命令安裝依賴:
1. Windows 環(huán)境 打開 Cmd (開始-運行-CMD)。
2. MacOS 環(huán)境 打開 Terminal (command+空格輸入Terminal)。
3. 如果你用的是 VSCode編輯器 或 Pycharm,可以直接使用界面下方的Terminal.
pip install?djangovue的安裝可見:
https://www.runoob.com/vue2/vue-install.html
創(chuàng)建前后端項目:創(chuàng)建一個文件夾,然后命令行創(chuàng)建項目即可,如下圖:

命令行進入后端文件夾 book_demo,輸入下面命令,瀏覽器登陸 127.0.0.1:8000 看見歡迎頁即成功。
python manage.py runserver再進入前端文件夾 appfront ,輸入下面命令,瀏覽器登陸 127.0.0.1:8080 看見歡迎頁即成功。
npm run dev上面兩個命令也是對應前后端項目的啟動命令,后面就直接將過程說成啟動前/后端項目。
2.后端實現(xiàn)
為了方便后端的實現(xiàn),作為django做后端api服務的一種常用插件,django-rest-framework(DRF)提供了許多好用的特性,所以本文demo中也應用一下,命令行輸入命令安裝:
pip install django-rest-framework進入book_demo目錄,創(chuàng)建一個新的名為books的應用,并在新應用中添加urls.py文件,方便后面的路由配置,命令行輸入:
python manage.py startapp books
cd?books
touch urls.py現(xiàn)在的目錄結(jié)構(gòu)如下:

下面開始做一些簡單的配置:
將DRF和books配置到django項目中,打開項目中的?settings.py?文件,添加:
# book_demo/settings.py
INSTALLED_APPS = [
????'django.contrib.admin',
????'django.contrib.auth',
????'django.contrib.contenttypes',
????'django.contrib.sessions',
????'django.contrib.messages',
????'django.contrib.staticfiles',
????# demo add
????'rest_framework',
????'books',
]對整個項目的路由進行配置,讓訪問 api/ 路徑時候轉(zhuǎn)到books應用中的urls.py文件配置進行處理。
# book_demo/settings.py
from?django.contrib import?admin
from?django.urls import?path, include
urlpatterns = [
????path('admin/', admin.site.urls),
????path('api/', include('books.urls')), # demo add
]下面在books應用中寫簡單的邏輯,demo只最簡單涉及對書本的增刪改查。因為這一部分不是本文重點,所以這里只介紹寫代碼流程和貼代碼,對代碼不做詳細解釋:
在models.py文件中寫簡單數(shù)據(jù)類Books:
# books/models.py
from?django.db import?models
class?Books(models.Model):
????name = models.CharField(max_length=30)
????author = models.CharField(max_length=30, blank=True, null=True)在books文件夾中創(chuàng)建serializer.py文件,并寫對應序列化器BooksSerializer:
# books/serializer.py
from?rest_framework import?serializers
from?books.models import?Books
class?BooksSerializer(serializers.ModelSerializer):
????class?Meta:
????????model = Books
????????fields = '__all__'在views.py文件中寫對應的視圖集BooksViewSet來處理請求:
# books/views.py
from?rest_framework import?viewsets
from?books.models import?Books
from?books.serializer import?BooksSerializer
class?BooksViewSet(viewsets.ModelViewSet):
????queryset = Books.objects.all()
????serializer_class = BooksSerializer在urls.py文件中寫對應的路由映射:
# books/urls.py
from?django.urls import?path, include
from?rest_framework.routers import?DefaultRouter
from?books import?views
router = DefaultRouter()
router.register('books', views.BooksViewSet)
urlpatterns = [
????path('', include(router.urls)),
]對于books應用中的內(nèi)容,如果對DRF和Django流程熟悉的同學肯定知道都干了些什么,篇幅關(guān)系這里只能簡單解釋,DRF通過視圖集ViewSet的方式讓我們對某一個數(shù)據(jù)類Model可以進行增刪改查,而且不同的操作對應于不同的請求方式,比如查看所有books用get方法,添加一本book用post方法等,讓整個后端服務是restful的。
如果實在看不懂代碼含義,只需知道這樣做之后就可以通過不同的網(wǎng)絡請求對后端數(shù)據(jù)庫的Books數(shù)據(jù)進行操作即可,后續(xù)可以結(jié)合Django和DRF官方文檔對代碼進行學習,或關(guān)注本人未來分享的內(nèi)容。
到這里,可以運行一下后端項目看看效果,命令行運行:
python manage.py makemigrations
python manage.py migrate
python manage.py runserver得益于DRF提供的api可視化界面,瀏覽器訪問?127.0.0.1:8000/api/books/?,如果出現(xiàn)了以下界面并添加數(shù)據(jù)正常,則說明后端的基本邏輯已經(jīng)ok了~下圖為添加了一條數(shù)據(jù)之后的效果。

3.前端實現(xiàn)
接下來的工作以appfront項目目錄為根目錄進行,開始寫一點前端的展示和表單,希望達到兩個目標,一是能從后端請求到所有的books列表,二是能往后端添加一條book數(shù)據(jù)。說白了就是希望把上面的頁面用Vue簡單實現(xiàn)一下,然后能達到相同的功能。
對于Vue項目中各個文件的功能這里也不多解釋,可以參考其文檔系統(tǒng)學習。這里只需要知道歡迎頁面中的樣式是寫在App.vue和components/HelloWorld.vue中即可。
這里直接用HelloWorld.vue進行修改,只求功能不追求頁面了~
上滑查看更多代碼
// appfront/src/components/HelloWorld.vue
<template>
??<div?class="hello">
????<h1>{{ msg }}</h1>
????<!-- show books list -->
????<ul>
??????<li?v-for="(book, index) in books"?:key="index"?style="display:block">
????????{{index}}-{{book.name}}-{{book.author}}
??????</li>
????</ul>
????<!-- form to add a book -->
????<form?action="">
??????輸入書名:<input?type="text"?placeholder="book name"?v-model="inputBook.name"><br>
??????輸入作者:<input?type="text"?placeholder="book author"?v-model="inputBook.author"><br>
????</form>
????<button?type="submit"?@click="bookSubmit()">submit</button>
??</div>
</template>
<script>
export?default?{
??name: 'HelloWorld',
??data () {
????return?{
??????msg: 'Welcome to Your Vue.js App',
??????// books list data
??????books: [
????????{name: 'test', author: 't'},
????????{name: 'test2', author: 't2'}
??????],
??????// book data in the form
??????inputBook: {
????????"name": "",
????????"author": "",
??????}
????}
??},
??methods: {
????loadBooks () {...}, // load books list when visit the page
????bookSubmit () {...} // add a book to backend when click the button
??},
??created: function?() {
????this.loadBooks()
??}
}
</script>
...
啟動前端項目,瀏覽器訪問127.0.0.1:8080,可以看到剛寫的頁面已經(jīng)更新上去了,丑是丑了點,意思到了就行~如下圖:

4.前后端聯(lián)調(diào)
敲黑板,重點來了!!上面的頁面中數(shù)據(jù)其實是寫死在前端頁面的模擬數(shù)據(jù),這一節(jié)希望通過從后端拿數(shù)據(jù)并展示在前端頁面的方式來完成前后端聯(lián)調(diào)。前后端聯(lián)調(diào),涉及最多的就是跨域的問題,為了保證安全,通常需要遵循同源策略,即“協(xié)議、域名、端口”三者都相同,具體可以看看相關(guān)的博客,這里只需知道上述三者相同才算同源即可。
后端部分,對于django的跨域問題,網(wǎng)上比較常用的做法就是利用django-cors-headers模塊來解決,這里也不能免俗,操作如下。
先在命令行中進行對應模塊的安裝:??????
pip install django-cors-headers
然后在項目中添加該模塊:
# books_demo/settings.py
INSTALLED_APPS = [
????...
????# demo
????'corsheaders',
????...
]
MIDDLEWARE = [
????'corsheaders.middleware.CorsMiddleware', # 需注意與其他中間件順序,這里放在最前面即可
????...
]
# 支持跨域配置開始
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True后端部分告于段落,接下來需要補充一下前端的邏輯,Vue框架現(xiàn)在一般都用axios模塊進行網(wǎng)絡請求,這里沿用這種方式,下面是在前端項目中操作:
首先命令行安裝axios模塊,如果沒有安裝cnpm就還是用npm安裝:
cnpm install axios為了方便管理api請求的各種邏輯,在前端項目的src目錄下創(chuàng)建api目錄,然后創(chuàng)建api.js和index.js文件。index.js文件是對axios做配置:
// appfront/src/api/index.js
import?Vue from?'vue'
import?Axios from?'axios'
const?axiosInstance = Axios.create({
????withCredentials: true
})
// 通過攔截器處理csrf問題,這里的正則和匹配下標可能需要根據(jù)實際情況小改動
axiosInstance.interceptors.request.use((config) =>?{
????config.headers['X-Requested-With'] = 'XMLHttpRequest'
????const?regex = /.*csrftoken=([^;.]*).*$/
????config.headers['X-CSRFToken'] = document.cookie.match(regex) === null?? null?: document.cookie.match(regex)[1]
????return?config
})
axiosInstance.interceptors.response.use(
????response?=>?{
????????return?response
????},
????error?=>?{
????????return?Promise.reject(error)
????}
)
Vue.prototype.axios = axiosInstance
export?default?axiosInstanceapi.js文件是對后端進行請求,可以看到,獲取books列表和添加一本book各對應于一個請求:
//?appfront/src/api/api.js
import?axiosInstance from?'./index'
const axios = axiosInstance
export?const getBooks = ()?=>?{return?axios.get(`http://localhost:8000/api/books/`)}
export?const postBook = (bookName, bookAuthor)?=>?{return?axios.post(`http://localhost:8000/api/books/`, {'name': bookName, 'author': bookAuthor})}
然后更新HelloWorld.vue中的處理邏輯:
// appfront/src/components/HelloWorld.vue
<script>
import?{getBooks, postBook} from?'../api/api.js'
export?default?{
??...
??methods: {
????loadBooks () {
??????getBooks().then(response?=>?{
????????this.books = response.data
??????})
????}, // load books list when visit the page
????bookSubmit () {
??????postBook(this.inputBook.name, this.inputBook.author).then(response?=>?{
????????console.log(response)
????????this.loadBooks()
??????})
????} // add a book to backend when click the button
??},
??...
}
</script>至此,一個極其簡陋的查詢和添加書籍的功能算是完成了~如下圖:


可以看到,列表里面的數(shù)據(jù)是從后端讀取到的,同時前端的提交數(shù)據(jù)庫也能有對應的操作,所以前后端至此是打通了。
5.打包??
現(xiàn)階段是前后端分開開發(fā),但是當最后要用的時候,還需要把代碼合在一起。
首先對前端項目進行打包,這里用Vue的自動打包:
npm run build可以看到前端項目中多出了一個dist文件夾,這個就是前端文件的打包結(jié)果。需要把dist文件夾復制到books_demo項目文件夾中。
然后對settings.py文件進行相應的修改,其實就是幫django指定模版文件和靜態(tài)文件的搜索地址:
# books_demo/books_demo/settings.py
...
TEMPLATES = [
????{
????????'BACKEND': 'django.template.backends.django.DjangoTemplates',
????????'DIRS': [os.path.join(BASE_DIR, 'dist')], # demo add
????????...
????},
]
...
STATICFILES_DIRS = [
????os.path.join(BASE_DIR, 'dist/static'),
]
..最后在根urls.py文件中配置一下入口html文件的對應路由:
# books_demo/books_demo/urls.py
...
from?django.views.generic.base import?TemplateView
urlpatterns = [
????...
????path('', TemplateView.as_view(template_name='index.html'))
]重新啟動項目,這次用瀏覽器訪問?127.0.0.1:8000?,即django服務的對應端口即可。
可以看到,項目的交互是正常的,符合我們的預期。
總結(jié)
本文以一個非常簡單的demo為例,介紹了利用django+drf+vue的前后端分離開發(fā)模式,基本可以算是手把手入門。有了這個小demo之后,不管是前端頁面還是后端功能,都可以做相應的擴展,從而開發(fā)出更加復雜使用的網(wǎng)站。
我們的文章到此就結(jié)束啦,如果你喜歡今天的Python 實戰(zhàn)教程,請持續(xù)關(guān)注Python實用寶典。
有任何問題,可以在公眾號后臺回復:加群,回答相應紅字驗證信息,進入互助群詢問。
原創(chuàng)不易,希望你能在下面點個贊和在看支持我繼續(xù)創(chuàng)作,謝謝!
點擊下方閱讀原文可獲得更好的閱讀體驗
Python實用寶典?(pythondict.com)
不只是一個寶典
歡迎關(guān)注公眾號:Python實用寶典
