实现Django与Vue.js的前后端分离架构可以显著提高Web应用的性能、可维护性和可扩展性。在这种架构中,Django 主要负责处理业务逻辑、数据访问和RESTful API的构建,而 Vue.js 则专注于用户界面的呈现和交互。下面是实现这一架构的一般步骤:
1. 构建后端:Django
- 创建Django项目:首先使用Django创建一个新的项目,这是你的后端基础。
- 设计模型:定义数据库模型,这些模型将被Vue.js前端通过API调用来获取或修改数据。
- 构建API:使用Django REST framework或其他类似库来创建RESTful API,这些API将数据以JSON格式暴露给前端。
- 安全和认证:实现认证机制,如基于令牌的认证(JWT),确保只有授权的用户才能访问特定的API端点。
2. 构建前端:Vue.js
- 创建Vue项目:使用Vue CLI或其他工具创建Vue.js项目。
- 状态管理:使用Vuex来管理复杂的状态,这在大型应用中特别有用。
- 路由:使用Vue Router来设置单页应用(SPA)中的导航和视图。
- 组件化:将UI分解成可重用的组件,每个组件负责单一职责。
- 请求API:使用Axios或Fetch API从Django后端获取数据并发送请求。
3. 前后端通信
- API调用:Vue前端通过HTTP请求与Django后端进行通信,通常是GET、POST、PUT、DELETE等HTTP方法。
- 数据绑定:Vue.js的双向数据绑定使得从前端到后端的数据传递变得简单。
- 错误处理:实现错误处理逻辑,当API请求失败时向用户提供反馈。
4. 部署和打包
- Webpack配置:使用Webpack来打包Vue.js应用,生成静态文件,这些文件可以被Django服务。
- 静态文件服务:Django可以配置为服务由Webpack生成的静态文件,包括HTML、CSS和JavaScript。
- 生产环境配置:确保在生产环境中,Django和Vue.js都配置得当,例如设置正确的域名和端口。
5. 测试
- 前端测试:使用如Jest或Mocha进行单元测试和集成测试。
- 后端测试:利用Django的测试框架进行单元测试和功能测试。
6. 持续集成/持续部署(CI/CD)
- 自动化构建和测试:设置CI/CD流水线,每次代码提交时自动构建和测试你的应用。
7. 性能优化
- 缓存策略:考虑在Django中使用缓存机制来加速API响应。
- 前端性能:使用懒加载、代码分割等技术来优化前端性能。
实现Django与Vue.js的前后端分离需要对两者都有深入的理解,同时也需要良好的项目组织结构和团队协作。这样的架构模式可以帮助你构建出可扩展、高性能的现代Web应用。
8.前后端分离之前
9.前后端分离之后
10. 实操后端部分
环境准备
Python3.7/Mysql5.7/Pycharm/Node/Django3.0
基础步骤
创建Django项目/数据迁移/更换数据库为Mysql
创建Django项目
(venv) ➜ django-admin startproject django_vue
同步数据库SQLite3
(venv) ➜ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
建库建表
mysql> CREATE DATABASE django_vue_db CHARACTER SET utf8;
安装mysql模块
(venv) ➜ pip install mysqlclient
配置settings.py文件,配置Mysql数据库引擎
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_vue_db',
'USER': 'root',
'PASSWORD': 'xxxxxxx',
'HOST': '127.0.0.1',
}
}
执行数据库同步
python manage.py migrate
创建APP
(venv) ➜ python manage.py startapp api_test
Settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api_test',
]
models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class Book(models.Model):
book_name = models.CharField(max_length=128)
add_time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.book_name
views.py
在api_test目录下的views里我们新增两个接口,一个是show_books返回所有的书籍列表(通过JsonResponse返回能被前端识别的json格式数据),二是add_book接受一个get请求,往数据库里添加一条book数据
from django.shortcuts import render
from django.views.decorators.http import require_http_methods
from django.core import serializers
from django.http import JsonResponse
import json
from .models import Book
@require_http_methods(["GET"])
def add_book(request):
response = {}
try:
book = Book(book_name=request.GET.get('book_name'))
book.save()
response['msg'] = 'success'
response['error_num'] = 0
except Exception as e:
response['msg'] = str(e)
response['error_num'] = 1
return JsonResponse(response)
@require_http_methods(["GET"])
def show_books(request):
response = {}
try:
books = Book.objects.filter()
response['list'] = json.loads(serializers.serialize("json", books))
response['msg'] = 'success'
response['error_num'] = 0
except Exception as e:
response['msg'] = str(e)
response['error_num'] = 1
return JsonResponse(response)
APP级urls.py
from django.conf.urls import url, include
from .views import *
urlpatterns = [
url(r'add_book$', add_book, ),
url(r'show_books$', show_books, ),
]
项目级urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
import api_test.urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(api_test.urls)),
]
同步数据库
python manage.py makemigrations api_test
python manage.py migrate
测试接口
http://127.0.0.1:8000/api/add_book/?book_name=davieyang
HTTP/1.1 200 OK
Content-Length: 34
Content-Type: application/json
Date: Sun, 15 Dec 2019 09:11:12 GMT
Server: WSGIServer/0.2 CPython/3.7.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"error_num": 0,
"msg": "success"
}
http://127.0.0.1:8000/api/add_book/?book_name=测试开发技术
HTTP/1.1 200 OK
Content-Length: 34
Content-Type: application/json
Date: Sun, 15 Dec 2019 09:11:44 GMT
Server: WSGIServer/0.2 CPython/3.7.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"error_num": 0,
"msg": "success"
}
调用接口,显示Django App中所有书名列表
http://127.0.0.1:8000/api/show_books
HTTP/1.1 200 OK
Content-Length: 305
Content-Type: application/json
Date: Sun, 15 Dec 2019 09:13:48 GMT
Server: WSGIServer/0.2 CPython/3.7.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"error_num": 0,
"list": [
{
"fields": {
"add_time": "2019-12-15T09:11:12.673Z",
"book_name": "mikezhou_talk"
},
"model": "api_test.book",
"pk": 1
},
{
"fields": {
"add_time": "2019-12-15T09:11:44.305Z",
"book_name": "测试开发技术"
},
"model": "api_test.book",
"pk": 2
}
],
"msg": "success"
}
11.实操Vue部分
环境准备
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g vue-cli
新建Vue工程
vue-init webpack frontend
安装 vue 依赖模块
cd frontend
cnpm install
cnpm install vue-resource
cnpm install element-ui
目录结构
- 在frontend目录src下包含入口文件main.js,入口组件App.vue等。后缀为vue的文件是Vue.js框架定义的单文件组件,其中标签中的内容可以理解为是类html的页面结构内容。
- 在src/component文件夹下新建一个名为Home.vue的组件,通过调用之前在Django上写好的api,实现添加书籍和展示书籍信息的功能。在样式组件上我们使用了饿了么团队推出的element-ui,这是一套专门匹配Vue.js框架的功能样式组件。由于组件的编码涉及到了很多js、html、css的知识,并不是本文的重点,因此在此只贴出部分代码:
Home.vue文件代码:
<template>
<div class="home">
<el-row display="margin-top:10px">
<el-input v-model="input" placeholder="请输入书名" style="display:inline-table; width: 30%; float:left"></el-input>
<el-button type="primary" @click="addBook()" style="float:left; margin: 2px;">新增</el-button>
</el-row>
<el-row>
<el-table :data="bookList" style="width: 100%" border>
<el-table-column prop="id" label="编号" min-width="100">
<template slot-scope="scope"> {{ scope.row.pk }} </template>
</el-table-column>
<el-table-column prop="book_name" label="书名" min-width="100">
<template slot-scope="scope"> {{ scope.row.fields.book_name }} </template>
</el-table-column>
<el-table-column prop="add_time" label="添加时间" min-width="100">
<template slot-scope="scope"> {{ scope.row.fields.add_time }} </template>
</el-table-column>
</el-table>
</el-row>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
input: '',
bookList: []
}
},
mounted: function () {
this.showBooks()
},
methods: {
addBook () {
this.$http.get('http://127.0.0.1:8000/api/add_book?book_name=' + this.input)
.then((response) => {
var res = JSON.parse(response.bodyText)
if (res.error_num === 0) {
this.showBooks()
} else {
this.$message.error('新增书籍失败,请重试')
console.log(res['msg'])
}
})
},
showBooks () {
this.$http.get('http://127.0.0.1:8000/api/show_books')
.then((response) => {
var res = JSON.parse(response.bodyText)
console.log(res)
if (res.error_num === 0) {
this.bookList = res['list']
} else {
this.$message.error('查询书籍失败')
console.log(res['msg'])
}
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
- 在src/router目录的index.js中,我们把新建的Home组件,配置到vue-router路由中:
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
}
]
})
- 在src/main.js文件中,导入element-ui、vue-resource库
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import VueResource from 'vue-resource'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
Vue.use(VueResource)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
- 如果出现跨域问题,需要在Django层注入header,用Django的第三方包django-cors-headers来解决跨域问题:
pip install django-cors-headers
settings.py 修改:
# 注意中间件的添加顺序
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True
在前端工程frontend目录下,输入npm run dev启动node自带的服务器,浏览器会自动打开, 我们能看到页面:
尝试新增书籍,如填入:“自动化测试实战宝典”,新增的书籍信息会实时反映到页面的列表中,这得益于Vue.js的数据双向绑定特性
在前端工程frontend目录下,输入npm run build,如果项目没有错误的话,就能够看到所有的组件、css、图片等都被webpack自动打包到dist目录下了:
整合Django和Vue.js前端
目前已经分别完成了Django后端和Vue.js前端工程的创建和编写,但实际上它们是运行在各自的服务器上,和我们的要求是不一致的。因此我们须要把Django的TemplateView指向我们刚才生成的前端dist文件即可
- 找到project目录的urls.py,使用通用视图创建最简单的模板控制器,访问 『/』时直接返回 index.html:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(api_test.urls)),
url(r'^$', TemplateView.as_view(template_name="index.html")),
]
- 上一步使用了Django的模板系统,所以需要配置一下模板使Django知道从哪里找到index.html。在project目录的settings.py下:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS':['frontend/dist'],
'APP_DIRS':True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
- 我们还需要配置一下静态文件的搜索路径。同样是project目录的settings.py下:
# Add for vuejs
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "frontend/dist/static"),
]
- 配置完成,我们在project目录下输入命令python manage.py runserver,就能够看到我们的前端页面在浏览器上展现:
注意:此时服务的端口已经是Django服务的8000而不是node服务的8080了,说明我们已经成功通过Django集成了Vue前端工程。示例充分展示了现在主流的前后端分离方式,由前端框架,如Vue.js来构建实现前端界面,再通过后端框架,如Django来实现API数据提供,两者通过接口进行通讯、相辅相成、最终实现一个完整Web项目.
12.Windows环境配置
Node.js
下载安装node.js, 官方下载地址https://nodejs.org/en/,下载符合自己操作系统版本的即可,安装也是傻瓜式安装。
安装完成后,在命令行输入node,如下展示则表示成功
C:\Users\Administrator>node -v
v8.17.0
配置cnpm并安装vue-cli
在命令行输入: npm install -g cnpm --registry=https://registry.npm.taobao.org (https://registry.npm.taobao.org/)
之后cnpm install -g vue-cli命令行展示如下内容,则表示成功
C:\Users\Administrator>npm install -g cnpm --registry=https://registry.npm.taobao.org
C:\Users\Administrator\AppData\Roaming\npm\cnpm -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\cnpm\bin\cnpm
+ cnpm@6.1.1
added 681 packages from 938 contributors in 30.737s
C:\Users\Administrator>cnpm install -g vue-cli
Downloading vue-cli to C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli_tmp
Copying C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli_tmp\_vue-cli@2.9.6@vue-cli to C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli
Installing vue-cli's dependencies to C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli/node_modules
[1/20] commander@^2.9.0 installed at node_modules\_commander@2.20.3@commander
[2/20] minimatch@^3.0.0 installed at node_modules\_minimatch@3.0.4@minimatch
[3/20] multimatch@^2.1.0 installed at node_modules\_multimatch@2.1.0@multimatch
[4/20] ora@^1.3.0 installed at node_modules\_ora@1.4.0@ora
[5/20] rimraf@^2.5.0 existed at node_modules\_rimraf@2.7.1@rimraf
[6/20] consolidate@^0.14.0 installed at node_modules\_consolidate@0.14.5@consolidate
[7/20] chalk@^2.1.0 installed at node_modules\_chalk@2.4.2@chalk
[8/20] semver@^5.1.0 installed at node_modules\_semver@5.7.1@semver
[9/20] uid@0.0.2 installed at node_modules\_uid@0.0.2@uid
[10/20] read-metadata@^1.0.0 installed at node_modules\_read-metadata@1.0.0@read-metadata
[11/20] user-home@^2.0.0 installed at node_modules\_user-home@2.0.0@user-home
[12/20] tildify@^1.2.0 installed at node_modules\_tildify@1.2.0@tildify
[13/20] coffee-script@1.12.7 existed at node_modules\_coffee-script@1.12.7@coffee-script
[14/20] handlebars@^4.0.5 installed at node_modules\_handlebars@4.5.3@handlebars
[15/20] validate-npm-package-name@^3.0.0 installed at node_modules\_validate-npm-package-name@3.0.0@validate-npm-package-name
[16/20] metalsmith@^2.1.0 installed at node_modules\_metalsmith@2.3.0@metalsmith
[17/20] download-git-repo@^1.0.1 installed at node_modules\_download-git-repo@1.1.0@download-git-repo
[18/20] request@^2.67.0 installed at node_modules\_request@2.88.0@request
[19/20] async@^2.4.0 installed at node_modules\_async@2.6.3@async
[20/20] inquirer@^6.0.0 installed at node_modules\_inquirer@6.5.2@inquirer
deprecate metalsmith@2.3.0 › gray-matter@2.1.1 › coffee-script@^1.12.4 CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
Recently updated (since 2019-12-30): 3 packages (detail see file C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli\node_modules\.recently_updates.txt)
Today:
→ request@2.88.0 › mime-types@~2.1.19(2.1.26) (11:47:55)
→ download-git-repo@1.1.0 › download@5.0.3 › decompress@4.2.0 › decompress-tar@4.1.1 › tar-stream@1.6.2 › readable-stream@^2.3.0(2.3.7) (01:13:39)
→ request@2.88.0 › mime-types@2.1.26 › mime-db@1.43.0(1.43.0) (11:24:37)
All packages installed (239 packages installed from npm registry, used 7s(network 7s), speed 703.07kB/s, json 223(445.45kB), tarball 4.55MB)
[vue-cli@2.9.6] link C:\Users\Administrator\AppData\Roaming\npm\vue@ -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli\bin\vue
[vue-cli@2.9.6] link C:\Users\Administrator\AppData\Roaming\npm\vue-init@ -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli\bin\vue-init
[vue-cli@2.9.6] link C:\Users\Administrator\AppData\Roaming\npm\vue-list@ -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue-cli\bin\vue-list
安装完成后,在命令行输入vue,如下所示,则表示成功
C:\Users\Administrator>vue
Usage: vue <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
init generate a new project from a template
list list available official templates
build prototype a new project
create (for v3 warning only)
help [cmd] display help for [cmd]
异常
deprecate element-ui@2.13.0 › async-validator@1.8.5 › babel-runtime@6.26.0 › core-js@^2.4.0 core-js@❤️ is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
(venv) D:\PythonPrograms\DjangoPrograms\DjangoVue\frontend>cnpm install element-ui
√ Installed 1 packages
√ Linked 10 latest versions
[1/1] scripts.postinstall element-ui@2.13.0 › async-validator@1.8.5 › babel-runtime@6.26.0 › core-js@^2.4.0 run "node -e \"try{require('./postinstall')}c
atch(e){}\"", root: "D:\\PythonPrograms\\DjangoPrograms\\DjangoVue\\frontend\\node_modules\\_core-js@2.6.11@core-js"
Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!
The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock
Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)
[1/1] scripts.postinstall element-ui@2.13.0 › async-validator@1.8.5 › babel-runtime@6.26.0 › core-js@^2.4.0 finished in 240ms
√ Run 1 scripts
deprecate element-ui@2.13.0 › async-validator@1.8.5 › babel-runtime@6.26.0 › core-js@^2.4.0 core-js@<3 is no longer maintained and not recommended for us
age due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
√ All packages installed (11 packages installed from npm registry, used 4s(network 4s), speed 23.04kB/s, json 11(87.37kB), tarball 0B)
在命令行输入
C:\Users\Administrator>cnpm install core-js@3
√ Installed 1 packages
√ Linked 0 latest versions
[1/1] scripts.postinstall core-js@3 run "node -e \"try{require('./postinstall')}catch(e){}\"", root: "C:\\Users\\Administrator\\node_modules\\_core-js@3.6.1@core-js"
[1/1] scripts.postinstall core-js@3 finished in 223ms
√ Run 1 scripts
√ All packages installed (1 packages installed from npm registry, used 2s(network 2s), speed 113.85kB/s, json 1(14.02kB), tarball 158.92kB)
再次执行命令:
(venv) D:\PythonPrograms\DjangoPrograms\DjangoVue\frontend>cnpm install element-ui
√ Installed 1 packages
√ Linked 0 latest versions
√ Run 0 scripts
√ All packages installed (used 539ms(network 536ms), speed 36.7kB/s, json 1(19.67kB), tarball 0B)
deprecate metalsmith@2.3.0 › gray-matter@2.1.1 › coffee-script@^1.12.4 CoffeeScript on NPM has moved to “coffeescript” (no hyphen)
执行如下命令解决:
C:\Users\Administrator>cnpm install coffeescript
√ Installed 1 packages
√ Linked 0 latest versions
√ Run 0 scripts
Recently updated (since 2019-12-30): 1 packages (detail see file C:\Users\Administrator\node_modules\.recently_updates.txt)
√ All packages installed (1 packages installed from npm registry, used 1s(network 1s), speed 343.98kB/s, json 1(5.39kB), tarball 361.29kB)