django vue 实战

django vue 实战


1. vue部分

1.1. 项目创建

创建vue项目
在django_vue项目根目录下,新建一个前端工程目录:

vue-init webpack frontend

奇怪的是win+R打开cmd命令行可以找到vue,在当前路径下打开cmd找不到vue

在创建项目的过程中会弹出一些与项目相关的选项需要回答,按照真实情况进行输入即可。

安装 vue 依赖模块

cd frontend
cnpm install
cnpm install vue-resource
cnpm install element-ui

django项目目录下新增frontend目录
此处是为了方便,一般前端项目与后端项目位于各自单独的代码仓库。

项目结构释义
在frontend目录src下包含入口文件main.js,入口组件App.vue等。后缀为vue的文件是Vue.js框架定义的单文件组件,其中标签中的内容可以理解为是类html的页面结构内容。

1.2. 代码编辑

在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="book_author" label="作者" min-width="100">  
<template slot-scope="scope"> {{ scope.row.fields.book_author }} </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:9001/demo/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:9001/demo/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 Home from '@/components/Home'  

Vue.use(Router)  

export default new Router({  
  routes: [  
    {  
      path: '/',  
      name: 'Home',  
      component: Home  
    }  
  ]  
})  

在src/main.js文件中,导入element-ui、vue-resource库。

  
// The Vue build version to load with the `import` command  
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.  
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  

MIDDLEWARE = [  
    'django.middleware.security.SecurityMiddleware',  
    'django.contrib.sessions.middleware.SessionMiddleware',  
    'corsheaders.middleware.CorsMiddleware',  # cros 跨域 注意位置  
    '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  

PS: 注意中间件的添加顺序。

1.3. 运行测试

前端项目frontend目录下,输入npm run dev启动node自带的服务器,访问
http://localhost:8080/#/

功能验证:
在默认的nodejs下方会出现书藉列表
新增书藉 vue项目实战 成功。新增的书籍信息会实时反映到页面的列表中,这得益于Vue.js的数据双向绑定特性。

PS:如果不启动django后端,前端获取不到项目并不会报错,只是列表为空;实际是前后端分别运行于不同server下。

2. 前端项目部署

在前端工程frontend目录下,执行
npm run build

如果项目没有错误的话,就能够看到所有的组件、css、图片等都被webpack自动打包到dist目录下了:

3. 整合Django和Vue.js前端

目前已经分别完成了Django后端和Vue.js前端部分,但实际上它们是运行在各自的服务器上。需要让Django直接使用相应的模板及静态文件。

找到project目录的urls.py,使用通用视图创建最简单的模板控制器,访问 『/』时直接返回 index.html:

  
# settings.py  
# 声明扩展模板路径  
TEMPLATES = [  
    {  
        'BACKEND': 'django.template.backends.django.DjangoTemplates',  
        'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'frontend/dist')],  
        'APP_DIRS': True,  
# 声明扩展静态文件路径  
STATICFILES_DIRS = [  
    os.path.join(BASE_DIR, "frontend/dist/static"),  
]  

# app_demo下的路由urls.py  
urlpatterns = [  
    path(route='', view=views.index, name='index'),  
    path(route='hello/', view=views.hello, name='hello_page'),  
    path(r'f', view=views.index),  
    path('add/', view=views.add, name='add'),  
    path(r'ajax_list/', views.ajax_list, name='ajax_list'),  
    path(r'ajax_dict/', views.ajax_dict, name='ajax_dict'),  
    path('add_book', views.add_book),  
    path('show_books', views.show_books),  
    path(r'show', TemplateView.as_view(template_name='index.html'))  
]  

访问http://127.0.0.1:9001/demo/show#/
结果正常

posted @ 2020-11-03 19:48  木林森__𣛧  阅读(1049)  评论(0)    收藏  举报