实现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.前后端分离之前

python前后端分离框架项目_Vue

9.前后端分离之后

python前后端分离框架项目_django_02

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

目录结构

python前后端分离框架项目_Vue_03

  • 在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自带的服务器,浏览器会自动打开, 我们能看到页面:

python前后端分离框架项目_python前后端分离框架项目_04


尝试新增书籍,如填入:“自动化测试实战宝典”,新增的书籍信息会实时反映到页面的列表中,这得益于Vue.js的数据双向绑定特性

python前后端分离框架项目_python_05


在前端工程frontend目录下,输入npm run build,如果项目没有错误的话,就能够看到所有的组件、css、图片等都被webpack自动打包到dist目录下了:

python前后端分离框架项目_Vue_06


整合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)