本篇将基于Django + Vue.js,手把手教大家快速的实现一个前后端分离的Web项目。文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
1. 前言
本篇将基于django + vue.js,手把手教大家快速的实现一个前后端分离的web项目。
	
2. 环境准备
- python 3.6.1
- mysql 5.7.23
- pycharm (专业版)
- node
	
3. 创建 django 项目
	 
 
创建完成后,目录结构如下所示
	 
 
使用 navicat 工具创建数据库 djangovue
	 
 
安装 mysqlclient 库
	 
 
	 
 
配置 settings.py 文件,配置 mysql 数据库引擎
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 | databases = {    'default': {        'engine': 'django.db.backends.mysql',        'name': 'djangovue',        'user': 'root',        'password': 'root',        'host': '127.0.0.1',    }} | 
执行同步操作,将数据迁移到 mysql
	 
 
启动 django server ,验证默认配置是否正常
| 
								1
							 | python manage.py runserver 0.0.0.0:8000 | 
	 
 
打开浏览器,访问 http://localhost:8000
	 
 
创建一个 app 作为项目后端
| 
								1
							 | python manage.py startapp backend | 
创建完成后,目录结构如下所示
	 
 
把 backend 加入到 settings.py 文件中的 installed_apps 列表里
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 | installed_apps = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',    'backend'] | 
在 backend/models.py 里写一个简单 model 如下
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 | from django.db import models# create your models here.class book(models.model):    # 如果没有指定主键的话django会自动新增一个自增id作为主键    bookname = models.charfield(max_length=128, verbose_name='书名')    createtime = models.datetimefield(auto_now_add=true, verbose_name='创建时间')    def __unicode__(self):        returnself.bookname    def __str__(self):        returnself.bookname | 
根据修改创建迁移文件,并应用这些修改到数据库中
| 
								1
							 
								2
							 
								3
							 
								4
							 | # 创建迁移文件python manage.py makemigrations# 应用修改到数据库python manage.py migrate | 
	 
 
django 生成的表名将以 app 名加上 model 中的类名组合而成,也可以自定义表名,如下
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 | from django.db import models# create your models here.class book(models.model):    bookname = models.charfield(max_length=128, verbose_name='书名')    createtime = models.datetimefield(auto_now_add=true, verbose_name='创建时间')    def __unicode__(self):        returnself.bookname    def __str__(self):        returnself.bookname    class meta:        db_table = 'backend_book' | 
在 backend/views 里我们新增两个接口,一个返回所有的书籍列表,一个往数据库里添加一条book数据。
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 
								18
							 
								19
							 
								20
							 
								21
							 
								22
							 
								23
							 
								24
							 
								25
							 
								26
							 
								27
							 
								28
							 
								29
							 
								30
							 
								31
							 
								32
							 
								33
							 
								34
							 
								35
							 
								36
							 
								37
							 | import jsonfrom django.core import serializersfrom django.http import jsonresponsefrom django.shortcuts import renderfrom django.views.decorators.http import require_http_methodsfrom backend.models import book@require_http_methods(["get"])def add_book(request):    response = {}    try:        book_name = request.get.get('book_name')        book = book(bookname=book_name)        book.save()        response['respmsg'] = 'success'        response['respcode'] = '000000'    except exception as e:        response['respmsg'] = str(e)        response['respcode'] = '999999'    returnjsonresponse(response)@require_http_methods(["get"])def show_books(request):    response = {}    try:        books = book.objects.filter()        response['list'] = json.loads(serializers.serialize("json", books))        response['respmsg'] = 'success'        response['respcode'] = '000000'    except exception as e:        response['respmsg'] = str(e)        response['respcode'] = '999999'    returnjsonresponse(response) | 
在 backend 目录下,新增一个 urls.py 文件,把我们新增的两个接口添加到路由里
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 | # -*- coding: utf-8 -*-"""-------------------------------------------------   file name :     urls.py   description :       author :         fhqi   date :          2021-08-19-------------------------------------------------"""from django.conf.urls import urlfrom backend.views import add_book, show_booksurlpatterns = [    url("add_book", add_book, ),    url("show_books", show_books, ),] | 
最后要把backend 下的 urls 添加到项目 djangovue 下的 urls 中,才算完成路由
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 | from django.contrib import adminfrom django.urls import path, includeurlpatterns = [    path('admin/', admin.site.urls),    path('api/', include('backend.urls')),] | 
重新启动服务,测试一下刚才写的两个接口
| 
								1
							 | python manage.py runserver 0.0.0.0:8000 | 
	 
 
	 
 
	
4. 创建 vue.js 前端项目
使用 node 自带的 npm 包管理器安装 vue 和相关模块。推荐使用淘宝的 cnpm 命令行工具代替默认的 npm。
| 
								1
							 | npm install -g cnpm --registry=https://registry.npm.taobao.org | 
安装 vue.js
| 
								1
							 | cnpm install -g vue | 
安装vue-cli脚手架工具(vue-cli是官方脚手架工具,能迅速帮你搭建起vue项目的框架)
| 
								1
							 | cnpm install -g vue-cli | 
在 djangovue 项目根目录下,新建一个前端工程目录
| 
								1
							 | vue-init webpack frontend | 
在创建项目的过程中会弹出一些与项目相关的选项需要回答,按照真实情况进行输入即可,如下:
project name(工程名):回车
project description(工程介绍):回车
author:作者名 :回车
vue build ==> (是否安装编译器)runtime-compiler、 runtime-only 都是打包方式,第二个效率更高;
install vue-router ==> 是否要安装 vue-router,项目中肯定要使用到路由,所以y 回车;
use eslint to lint your code ==> 是否需要eslint检测代码,目前我们不需要所以 n 回车;
set up unit tests ==> 是否安装 单元测试工具 目前我们不需要 所以 n 回车;
setup e2e tests with nightwatch ==>是否需要端到端测试工具目前我们不需要所以n回车;
should we run npm install for you after the project has been created? (recommended) (use arrow keys)==> 安装依赖npm install
回车;
	 
 
安装 vue 依赖模块
| 
								1
							 
								2
							 
								3
							 
								4
							 | cd frontendcnpm installcnpm install vue-resourcecnpm install element-ui | 
现在整个文件目录结构如下
	 
 
在 frontend 目录 src 下包含入口文件 main.js,入口组件 app.vue 等。后缀为 vue 的是 vue.js 框架定义的单文件组件,一个文件包含且仅包含三块内容,如下:
	1. <template></template > 前端渲染的模板
2. 专为此模板写渲染逻辑的 <script></script>
3. 专为此模板写样式的 <style></style>
在 src/components 文件夹下新建一个名为 home.vue 的组件,通过调用之前在 django 上写好的 api,实现添加书籍和展示书籍信息的功能。在样式组件上我们使用了饿了么团队推出的 element-ui,这是一套专门匹配 vue.js 框架的功能样式组件。由于组件的编码涉及到了很多 js、html、css 的知识,并不是本文的重点,因此在此只贴出部分代码。
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 
								18
							 
								19
							 
								20
							 
								21
							 
								22
							 
								23
							 
								24
							 
								25
							 
								26
							 
								27
							 
								28
							 
								29
							 
								30
							 
								31
							 
								32
							 
								33
							 
								34
							 
								35
							 
								36
							 
								37
							 
								38
							 
								39
							 
								40
							 
								41
							 
								42
							 
								43
							 
								44
							 
								45
							 
								46
							 
								47
							 
								48
							 
								49
							 
								50
							 
								51
							 
								52
							 
								53
							 
								54
							 
								55
							 
								56
							 
								57
							 
								58
							 
								59
							 
								60
							 
								61
							 
								62
							 
								63
							 
								64
							 
								65
							 
								66
							 
								67
							 
								68
							 
								69
							 
								70
							 
								71
							 
								72
							 
								73
							 
								74
							 
								75
							 
								76
							 
								77
							 
								78
							 
								79
							 
								80
							 
								81
							 
								82
							 
								83
							 | <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="bookname"label="书名"min-width="100"><template slot-scope="scope"> {{ scope.row.fields.bookname }} </template></el-table-column><el-table-column prop="createtime"label="添加时间"min-width="100"><template slot-scope="scope"> {{ scope.row.fields.createtime }} </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) => {          varres = json.parse(response.bodytext)          if(res.respcode === '000000') {            this.showbooks()          } else{            this.$message.error('新增书籍失败,请重试')            console.log(res['respmsg'])          }        })    },    showbooks () {      this.$http.get('http://127.0.0.1:8000/api/show_books')        .then((response) => {          varres = json.parse(response.bodytext)          console.log(res)          if(res.respcode === '000000') {            this.booklist = res['list']          } else{            this.$message.error('查询书籍失败')            console.log(res['respmsg'])          }        })    }  }}</script><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 路由中
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 
								18
							 | import vue from 'vue'import router from 'vue-router'// import helloworld from '@/components/helloworld'import home from '@/components/home'vue.use(router)export defaultnewrouter({  routes: [    {      path: '/',      // name: 'helloworld',      name: 'home',      // component: helloworld      component: home    }  ]}) | 
在 src/main.js 文件中,导入 element-ui、vue-resource 库。
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 
								17
							 
								18
							 | 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 */newvue({  el: '#app',  router,  render: h => h(app)}) | 
	在前端工程 frontend 目录下,输入 npm run dev 启动 node 自带的服务器,自动打开浏览器,如下页面:
	 
 
	
5. 解决跨域问题
此时出现了一个问题,数据是空的,打开开发者工具,发现有错误。因为我们使用 vuejs 的开发环境脱离了 django 环境,访问 django 写的 api,出现了跨域问题,有两种方法解决,一种是在 vuejs 层上做转发(proxytable),另一种是在 django 层注入 header,这里使用后者,用 django 的第三方包 django-cors-headers 来解决跨域问题。
| 
								1
							 | pip install django-cors-headers | 
修改 settings.py
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 | middleware = [    'django.middleware.security.securitymiddleware',    'django.contrib.sessions.middleware.sessionmiddleware',    'corsheaders.middleware.corsmiddleware',# 添加1,注意中间件的添加顺序    '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# 添加2 | 
至此,页面上有数据了,如下:
	 
 
新增书籍,如填入:“django从入门到放弃”,新增的书籍信息会实时反映到页面的列表中,这得益于vue.js的数据双向绑定特性。
	 
 
	
6. 整合 django 和 vue.js 前端
目前我们已经分别完成了 django 后端和 vue.js 前端工程的创建和编写,但实际上它们是运行在各自的服务器上,和我们的要求是不一致的。
	在前端工程 frontend 目录下,输入 npm run build,如果项目没有错误的话,就能够看到所有的组件、css、图片等都被 webpack 自动打包到 dist 目录下了,里面有一个 index.html 和一个文件夹 static。
	 
 
修改 djangovue 下的 urls ,使用通用视图创建最简单的模板控制器,访问 『/』时直接返回 index.html
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 | from django.contrib import adminfrom django.urls import path, includefrom django.views.generic import templateviewurlpatterns = [    path('admin/', admin.site.urls),    path('api/', include('backend.urls')),    path(r'', templateview.as_view(template_name="index.html")),] | 
配置 django 项目的模板搜索路径。上一步使用了 django 的模板系统,所以需要配置一下模板使 django 知道从哪里找到 index.html。修改 settings.py 文件,如下:
| 
								1
							 
								2
							 
								3
							 
								4
							 
								5
							 
								6
							 
								7
							 
								8
							 
								9
							 
								10
							 
								11
							 
								12
							 
								13
							 
								14
							 
								15
							 
								16
							 | templates = [    {        'backend': 'django.template.backends.django.djangotemplates',        # 'dirs': [os.path.join(base_dir, 'templates')],        'dirs': [os.path.join(base_dir, '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',            ],        },    },] | 
配置静态文件的搜索路径。
| 
								1
							 
								2
							 
								3
							 
								4
							 | # add for vuejsstaticfiles_dirs = [    os.path.join(base_dir, "frontend/dist/static"),] | 
	配置完成,启动 django 服务 python manage.py runserver,就能够看到我们的前端页面在浏览器上展现:
	 
 
此时服务的端口已经是 django 服务的 8000 而不是 node 服务的 8080 了,说明我们已经成功通过 django 集成了 vue 前端工程。
到此这篇关于手把手教你使用django + vue.js 快速构建项目的文章就介绍到这了,更多相关django vue.js构建项目内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://blog.csdn.net/hwijew/article/details/119803456
- 本文固定链接: https://oversea.maimengkong.com/morejc/1361.html
- 转载请注明: : 萌小白 2023年1月27日 于 卖萌控的博客 发表
- 百度已收录

