pycharm+python+django+vue+elementUi搭建web项目

本篇使用Vue.js作为前端框架,代替Django本身较为孱弱的模板引擎,Django则作为服务端提供api接口,使得前后端实现完全分离,更适合单页应用的开发构建。

一、环境准备
pycharm、python、django、node.js、mysql。这些工具的安装这里不做赘述,百度都有。

二、新建django项目
在这里插入图片描述
在这里插入图片描述
三、运行项目,测试以下django项目是否新建成功

方法一:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法二:
在这里插入图片描述
在这里插入图片描述
四、修改数据库配置(我不想用django本身自带的db.sqlite3,想用自己在阿里云搭建的mysql)
在这里插入图片描述
修改后:

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_vue_elementUi',
        'USER': 'user',
        'PASSWORD': 'password',
        'HOST': '110.110.110.110',
    }
}

五、设计数据库表
在myDjangoApp下的models.py设计表

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models

# Create your models here.


class Book(models.Model):
    book_name = models.CharField(max_length=64)
    create_time = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.book_name

六、在myDjangoApp下的views.py新增两个接口

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json
from django.http import JsonResponse
from django.core import serializers
from django.shortcuts import render
from django.views.decorators.http import require_http_methods

from models import Book
# Create your views here.
# add_book接受一个get请求,往数据库里添加一条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, e:
        response['msg'] = str(e)
        response['error_num'] = 1

    return JsonResponse(response)


# show_books返回所有的书籍列表(通过JsonResponse返回能被前端识别的json格式数据)
@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, e:
        response['msg'] = str(e)
        response['error_num'] = 1

    return JsonResponse(response)

七、添加路由
1、在myDjangoApp目录下,新增一个urls.py文件,把新增的两个接口添加到路由里面(在django_vue_elementUi目录下的urls.py也可以直接加上这两个接口的路由,但是为了不使该主路由过于臃肿,所以这里要新建一个分支路由)

from django.conf.urls import url
import views

urlpatterns = [
    url(r'^add_book/', views.add_book),
    url(r'^show_books/', views.show_books),
]

2、把这个分支路由加到主路由中,在django_vue_elementUi目录下的urls.py中添加如下代码

from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from myDjangoApp import urls

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include(urls)),
]

八、新建数据库django_vue_elementUi
在这里插入图片描述
九、生成数据库迁移文件并且执行迁移文件来完成数据库表的创建
在这里插入图片描述
发现报错了
在这里插入图片描述
报错原因是因为没有安装MySQLdb,所以要进入命令行页面去执行pip install PyMySQL

在这里插入图片描述
安装成功后在django_vue_elementUi目录下的__init__.py中加入

import pymysql

pymysql.install_as_MySQLdb()

再执行数据库迁移文件生成命令makemigrations,生成迁移文件
在这里插入图片描述
执行迁移文件migrate
在这里插入图片描述
验证数据库表是否真的生成
在这里插入图片描述
如上图数据表与字段都已经创建成功了,但是会发现多了一个字段id,且id还是主键,但是我的models.py并没有设置这个字段。为什么呢?
答案:django默认在makemigrations会为表对象创建主键id,id = models.AutoField(primary_key=True)。如果你在models.py已经创建过主键的话就不会自动创建这个id主键了。

十、启项目测试接口是否能用
执行runserver,用postman调用接口
在这里插入图片描述
在这里插入图片描述
数据已经入库,表示这个添加图书的接口已经测试成功,那么测试以下查询的接口
在这里插入图片描述
查询接口也已经ok。

十一、把项目停掉,构建前端Vue项目
1、先安装vue-cli脚手架,再创建vue工程目录

 npm install -g vue-cli

在这里插入图片描述
2、安装好后,在django_vue_elementUi项目根目录下,新建一个前端工程目录:

 vue-init webpack appfront

在这里插入图片描述
3、进入appfront目录安装vue所需要的依赖

npm install

在这里插入图片描述
前端项目已经构建完成

十二、新建一个新组件来调用自己写好的api
我们在src/component文件夹下新建一个名为Book.vue的组件,通过调用之前在Django上写好的api,实现添加书籍和展示书籍信息的功能
1、新建组件
在这里插入图片描述
2、修改代码

<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 scope="scope"> {{ scope.row.pk }} </template>
          </el-table-column>
          <el-table-column prop="book_name" label="书名" min-width="100">
            <template scope="scope"> {{ scope.row.fields.book_name }} </template>
          </el-table-column>
          <el-table-column prop="add_time" label="添加时间" min-width="100">
            <template scope="scope"> {{ scope.row.fields.create_time }} </template>
          </el-table-column>
        </el-table>
    </el-row>
  </div>
</template>

<script>
export default {
  name: 'Book',
  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>

3、配置路由
在这里插入图片描述

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Book from '@/components/Book'

Vue.use(Router)

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

4、安装element-ui

npm i element-ui -S

在这里插入图片描述
十三、使用 webpack 打包vue项目

npm run build

在这里插入图片描述
启前端项目

npm run dev

在这里插入图片描述
浏览器打开网址会跳转默认首页,说明前端项目已经构建成功
在这里插入图片描述
加上book的路由后访问
在这里插入图片描述
发现展现的页面不是自己想要的,打开谷歌浏览器调试器
在这里插入图片描述
根据错误提示,是说elementUi的组件没有正确的注册,那么去appfront/src/main.js注册
在这里插入图片描述

// 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 '../node_modules/element-ui/lib/theme-chalk/index.css'
import ElementUI from 'element-ui'

Vue.config.productionTip = false
Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

保存后再去执行一次

npm run build
npm run dev

刷新页面发现我们的ui已经出来了,大功告成。
在这里插入图片描述
十四、整合django与Vue,使他们成为一个整体
目前我们已经分别完成了Django后端和Vue.js前端工程的创建和编写,但实际上它们是运行在各自的服务器上,和我们的要求是不一致的。因此我们须要把Django的TemplateView指向我们刚才生成的前端dist文件即可。

1、使用Django的通用视图 TemplateView修改静态指向路径
在这里插入图片描述

from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from myDjangoApp import urls
#新增
from django.views.generic import TemplateView   

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include(urls)),
    #新增
    url(r'^vue/', TemplateView.as_view(template_name="index.html"))  
]

2、修改静态资源文件路径
在这里插入图片描述
启django项目,

python manage.py runserver

用浏览器打开http://localhost:8000/vue/#/book
注意服务的端口已经是Django服务的8000而不是node服务的8080了!
在这里插入图片描述
但是为什么没有数据显示出来?数据库中明明有一条数据的,而且新增功能也不能用
在这里插入图片描述
所以再次打开谷歌浏览器的调试器
在这里插入图片描述
他说我Book.vue组件里的get没有定义,那么我们回到Book.vue看代码
在这里插入图片描述
原来是$http不能被解析,百度大法后得知前端要调用后端需要引入vue-resource
那么先来安装vue-resource再去引用

npm install --save vue-resource

在这里插入图片描述
如果发现列表抓取不到数据,可能是出现了跨域问题,打开浏览器console确认:
在这里插入图片描述
这时候我们须要在Django层注入header,用Django的第三方包django-cors-headers来解决跨域问题:

pip install django-cors-headers

在这里插入图片描述
settings.py 修改:
在这里插入图片描述
重新build

npm run build

重新run

python manage.py runserver

在这里插入图片描述
数据已经加载出来了,那么测试下添加的功能
在这里插入图片描述
一切ok。

  • 45
    点赞
  • 228
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值