阅读目录(Content)

  • 1. Vue+Django+DRF项目搭建案例
  • 1.1 企业的web项目类型
  • 1.2 企业项目开发流程
  • 1.3 立项申请阶段
  • 2. 需求分析
  • 2.1 首页
  • 2.2 登录注册
  • 2.3 课程列表
  • 2.4 课程详情
  • 2.5 购物车
  • 2.6 商品结算
  • 2.7 购买成功
  • 2.8 个人中心
  • 2.9 视频播放
  • 3. 环境搭建
  • 3.1 创建虚拟环境
  • 3.2 相关命令复习
  • 3.3 依赖包安装
  • 4. 搭建项目
  • 4.1 创建项目
  • 4.3 打开项目
  • 4.2 调整目录
    • 4.2.1 分不同环境进行项目配置
  • 4.3 创建代码版本
    • 4.3.1 配置用户名和邮箱
  • 4.4 在git平台创建工程
  • 4.5 日志配置
  • 4.6 异常处理
  • 4.7 创建数据库
  • 4.8 配置数据库连接
  • 5. 搭建前端项目
  • 5.1 创建项目目录
  • 5.2 初始化前端项目
  • 5.3 安装路由vue-router
    • 5.3.1 下载路由组件
    • 5.3.2 配置路由
  • 5.4 前端初始化全局变量和全局方法
  • 5.5 引入ElementUI
    • 5.5.1 配置ElementUI到项目中
  • 6. 跨域CORS


回到顶部(go to top)

1. Vue+Django+DRF项目搭建案例


1.1 企业的web项目类型

  1. 商城
    1.1 B2C 直销商城 商家与会员直接交易 ( Business To Customer )
    1.2 B2B 批发商城 商家与商家直接交易
    1.3 B2B2C 购物平台 商家和会员在另一个商家提供的平台上面进行交易
    1.4 C2B 定制商城 会员向商家发起定制商品的需求,商家去完成。
    1.5 O2O 线上线下交易平台
    1.6 C2C 二手交易平台
  2. 门户网站[企业站和门户站]
  3. 社交网络
  4. 资讯论坛
  5. 内部系统
  6. 个人博客
  7. 内容收费站


1.2 企业项目开发流程

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM

自动化运维平台SysOM 自动化运维平台 vue+drf_git_02


1.3 立项申请阶段

立项其实就是对产品项目能不能做和怎么做,提出理论基础。大的互联网公司都有比较正规的立项流程。

自动化运维平台SysOM 自动化运维平台 vue+drf_git_03

通常公司内部要研发一款软硬件的产品之前,都要经过市场评估和调研分析,产生一份产品项目立项报告给公司。

产品项目立项报告一般包含以下内容:

项目概述
需求市场
需求分析和项目建设的必要性
业务分析
总体建设方案
项目风险和风险管理
可行性分析阶段

参考资料:

回到顶部(go to top)

2. 需求分析


2.1 首页

功能:导航菜单、轮播图、退出登录

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_04


2.2 登录注册

功能:用户登录、极验验证码、多条件登录、记住密码、短信发送、短信冷却倒计时、jwt认证

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_05

自动化运维平台SysOM 自动化运维平台 vue+drf_git_06


2.3 课程列表

功能:课程分类、课程列表、课程多条件筛选展示、课程分类展示、课程分页展示、课程章节课时展示、课程优惠策略

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_07


2.4 课程详情

功能:课程信息展示、视频播放、富文本编辑器

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_08


2.5 购物车

功能:购物车商品列表、添加商品、删除商品、勾选商品状态、商品结算、订单生成、唯一订单号生成

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_09


2.6 商品结算

功能:订单商品信息列表、订单信息展示、积分计算功能、优惠券策略、课程有效期计算、第三方支付平台接口

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_10


2.7 购买成功

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_11


2.8 个人中心

功能列表:我的订单、订单状态改变

自动化运维平台SysOM 自动化运维平台 vue+drf_git_12


2.9 视频播放

功能:视频加密播放

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_13

回到顶部(go to top)

3. 环境搭建


3.1 创建虚拟环境

mkvirtualenv luffy

如果自己的开发机子中存在多个版本的python,则可以指定解析器的版本

mkvirtualenv luffy -p python3

自动化运维平台SysOM 自动化运维平台 vue+drf_git_14


3.2 相关命令复习

创建虚拟环境:               mkvirtualenv 虚拟环境名称
创建虚拟环境(指定python版本): mkvirtualenv -p python3 虚拟环境名称
查看所有虚拟环境:            workon+2次tab键
使用虚拟环境:               workon 虚拟环境名称
退出虚拟环境:               deactivate
删除虚拟环境(必须先退出虚拟环境内部才能删除当前虚拟环境):
                            rmvirtualenv 虚拟环境名称

其他相关命令:

查看虚拟环境中安装的包:              pip freeze  或者 pip list

收集当前环境中安装的包及其版本:       pip freeze > requirements.txt

在部署项目的服务器中安装项目使用的模块: pip install -r requirements.txt

提示:

  • 虚拟环境只会管理环境内部的模块和python解析器,对于源代码是毫无关系
  • 创建虚拟环境需要联网
  • 创建成功后, 会自动工作在这个虚拟环境上
  • 工作在虚拟环境上, 提示符最前面会出现 “(虚拟环境名称)”


3.3 依赖包安装

pip install django
pip install djangorestframework
pip install PymySQL
pip install Pillow

pip install django-redis

回到顶部(go to top)

4. 搭建项目


4.1 创建项目

django-admin startproject luffy

效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_15


4.3 打开项目

在pycharm中打开项目

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_16

设置虚拟环境

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_17

自动化运维平台SysOM 自动化运维平台 vue+drf_git_18

启动django项目

use the manage.py not pycharm default start button

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_19

效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_20

提示:

在pycharm中如果要使用已经创建好的虚拟环境,则必须设置pycharm中的python解释器,设置为虚拟环境中的python。


4.2 调整目录

├── docs/          # 项目相关资料保存目录
├── logs/          # 项目运行时/开发时日志目录
├── manage.py
├── luffy/         # 项目主应用,开发时的代码保存
│   ├── apps/      # 开发者的代码保存目录,以模块[子应用]为目录保存
│   ├── libs/      # 第三方类库的保存目录[第三方组件、模块]
│   ├── settings/
│       ├── dev.py   # 项目开发时的本地配置
│       ├── prop.py  # 项目上线时的运行配置
│   ├── urls.py    # 总路由
│   ├── utils/     # 多个模块[子应用]的公共函数类库[自己开发的组件]
└── scripts/       # 保存项目运营时的脚本文件

自动化运维平台SysOM 自动化运维平台 vue+drf_git_21


4.2.1 分不同环境进行项目配置

开发者本地的环境、目录、数据库密码和线上的服务器都会不一样,所以我们的配置文件可以针对不同的系统分成多分.

  1. 在项目主应用下,创建一个settings的配置文件存储目录
  2. 根据线上线下两种情况分别创建2个配置文件 dev.py和prod.py
  3. 把原来项目主应用的 settings.py配置内容复制2份到dev.py和prod.py里面
  4. 把原来的settings.py配置文件修改文件名或者删除

新的目录settings:

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_22

接下来,就可以根据在manage.py中根据不同的情况导入对应的配置文件了.

自动化运维平台SysOM 自动化运维平台 vue+drf_git_23


4.3 创建代码版本

cd进入到自己希望存储代码的目录路径,并创建本地仓库.git【pycharm直接打开终端就是项目根目录了。无须cd了】
新创建的本地仓库.git是个空仓库

cd 目录路径
git init


4.3.1 配置用户名和邮箱

git config --global user.name 'lisi'
git config --global user.email 'lisi@163.com'


4.4 在git平台创建工程

公司一般都会有自己的代码仓库,一般都是自己搭建,也有使用第三方提供代码管理平台。

常用的代码管理平台:github、gitee(码云)

如果公司自己搭建的代码管理平台,gitlab框架

1) 创建私有项目库

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_24

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_25

创建私有空仓库以后的界面:

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_26

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_27

2)克隆项目到本地

注意:
    我们当前项目不需要这个步骤
    这个步骤是 当以后我们进入公司里面,参与人家已经在做的项目时,别人已经有仓库了,但是我们是新人加入项目中的,那么我们不需要在自己本地进行git init,直接git clone 复制别人的仓库代码
git clone 仓库地址
注意,如果当前目录下出现git仓库同名目录时,会克隆失败。

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_28

3)创建并切换分支到dev

# git branch dev      # 创建本地分支dev,dev是自定义
# git checkout dev    # 切换本地分支代码
git checkout -b dev   # 这里是上面两句代码的简写

git提交

git add 代码目录   # 添加代码到上传队列
git status        # 查看当前项目的版本状态
git commit -m '添加项目代码'  # 提交代码到本地仓库, -m 表示本次提交的描述

推送到远端

git push origin dev:dev

如果推送代码,出现以下提示: git pull ....,则表示当前本地的代码和线上的代码版本不同.

1. 把线上的代码执行以下命令,拉取到本地,进行同步
git pull

2. 根据提示,移除多余的冲突的文件,也可以删除.

完成这些步骤以后,再次add,commit,push即可.

接下来,我们就把上面创建好的本地项目提交到gitee码云上面

# .表示当前目录下所有的文件或目录提交到上传队列[上传队列也叫"暂存区"]
git add .
# 把本地上传队列的代码提交到本地仓库

git commit -m "项目初始化搭建"
# 给本地的git版本控制软件设置项目的远程仓库地址

git remote add origin https://gitee.com/mooluo/luffyproject.git

# 提交代码给远程仓库

git push -u origin master
扩展:
1. 通过 git status 可以查看当前项目的代码版本状态
2. 通过 git reflog 可以查看代码版本日志[简单格式]
3. 通过 git log    可以查看代码版本日志[详细格式]

最终,成功提交了代码版本到gitee平台。效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_git_29

上面虽然成功移交了代码版本,但是一些不需要的文件也被提交上去了。

所以,我们针对一些不需要的文件,可以选择从代码版本中删除,并且使用.gitignore把这些垃圾文件过滤掉。

git rm 文件  # 删除单个文件
git rm -rf 目录  # 递归删除目录

# 以下操作建议通过ubuntu的终端来完成,不要使用pycharm提供,否则删除.idea还会继续生成。

git rm -rf .idea

git rm db.sqlite3
# 注意,上面的操作只是从项目的源代码中删除,但是git是不知情的,所以我们需要同步。

git add .

git commit -m "删除不必要的文件或目录"

git push -u origin master

使用.gitignore把一些垃圾文件过滤掉。

vim .gitignore

./idea

./idea/*

./git

./db.sqlite3

开发时我们经常会使用pycharm的提供的git管理工具来完成代码的拉取和推送。

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_30


4.5 日志配置

在settings/dev.py文件中追加如下配置:

# 日志配置
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志位置,日志文件名,日志保存目录必须手动创建
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs/luffy.log"),
            # 日志文件的最大值,这里我们设置300M
            'maxBytes': 300 * 1024 * 1024,
            # 日志文件的数量,设置最大日志数量为10
            'backupCount': 10,
            # 日志格式:详细格式
            'formatter': 'verbose'
        },
    },
    # 日志对象
    'loggers': {
        'luffy': {
            'handlers': ['console', 'file'],
            'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}


4.6 异常处理

新建utils/exceptions.py

from rest_framework.views import exception_handler
from django.db import DatabaseError
from rest_framework.response import Response
from rest_framework import status
import logging

logger = logging.getLogger('luffy')
def custom_exception_handler(exc, context):
"""

自定义异常处理

:param exc: 异常类

:param context: 抛出异常的上下文

:return: Response响应对象

"""
# 调用drf框架原生的异常处理方法

response = exception_handler(exc, context)
<span >if</span> response <span >is</span> <span >None</span>:
    view = context[<span >'view'</span>]
    <span >if</span> isinstance(exc, DatabaseError):
        <span ># 数据库异常</span>
        logger.error(<span >'[%s] %s'</span> % (view, exc))
        response = Response({<span >'message'</span>: <span >'服务器内部错误'</span>}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

<span >return</span> response</code></pre>

settings/dev.py配置文件中添加
REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
}

4.7 创建数据库
create database luffycity default charset=utf8;

为当前项目创建数据库用户[这个用户只能看到这个数据库]
create user luffy_user identified by 'luffy';
grant all privileges on luffycity.* to 'luffy_user'@'%';
flush privileges;


4.8 配置数据库连接
打开settings/dev.py文件,并配置
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "luffy_user",
        "PASSWORD": "luffy",
        "NAME": "luffycity",
    }
}
在项目主模块的 __init__.py中导入pymysql
import pymysql
pymysql.install_as_MySQLdb()

调整错误
数据库版本检测导致的错误

数据库的版本检测代码注释掉。、

第二个错误也是因为数据库版本的默认编码导致,query返回的内容格式使用有误。
新增一行代码,把query查询结果转换格式为 bytes类型


回到顶部(go to top)

5. 搭建前端项目

5.1 创建项目目录
cd 项目目录
vue init webpack lufei_pc
例如,我要把项目保存在~/Desktop桌面目录下,可以如下操作:
cd ~/Desktop
vue init webpack lufei_pc
根据需要在生成项目时,我们选择对应的选项, 效果:

根据上面的提示,我们已经把vue项目构建好了,运行测试服务器。

打开项目已经,在pycharm的终端下运行vue项目,查看效果。
npm run dev
接下来,我们根据终端上效果显示的对应地址来访问项目(如果有多个vue项目在运行,8080端口被占据了,服务器会自动改端口,所以根据自己实际在操作中看到的地址来访问。)
访问:http://localost:8080。效果:

我们也可以把我们的前端项目进行git源代码管理

5.2 初始化前端项目
清除默认的HelloWorld组件和APP.vue中的默认样式

接下来,我们可以查看效果了,一张白纸~


5.3 安装路由vue-router

5.3.1 下载路由组件
npm i vue-router -S
执行效果:


5.3.2 配置路由
5.3.2.1 初始化路由对象
在src目录下创建routers路由目录,在routers目录下创建index.js路由文件
index.js路由文件中,编写初始化路由对象的代码 .
import Vue from "vue"
import Router from "vue-router"
// 这里导入可以让让用户访问的组件
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#

mode: "history",
routes:[
// 路由列表
]

})



5.3.2.2 注册路由信息
打开main.js文件,把router对象注册到vue中.代码:
// 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 './routers/index';
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',

router,
components: { App },
template: '<App/>'

});



5.3.2.3 在视图中显示路由对应的内容
在App.vue组件中,添加显示路由对应的内容。

代码:
<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
export default {
name: 'App',
components: {
}

}
</script>
<style>
</style>


5.3.2.4 创建并提供前端首页的组件
routers/index.js
// import Vue from "vue"
// import Router from "vue-router"
//
//
// // 这里导入可以让让用户访问的组件
import Home from "../components/Home"
// Vue.use(Router);
//
// export default new Router({
//   // 设置路由模式为‘history’,去掉默认的#
//   mode: "history",
//   routes:[
//     // 路由列表
     {
       name:"Home",
       path:"/",
       component:Home,
     },
      {
       name:"Home",
       path:"/home",
       component:Home,
     },
   ]
// })

创建Home组件
components/Home.vue
<template>
  <div id="home">
    前端首页
  </div>
</template>
<script>
  export default {
      name:"Home",
      data(){
          return {
      }
  }

}
</script>
<style scoped>
</style>




5.4 前端初始化全局变量和全局方法
在src目录下创建settings.js站点开发配置文件:
export default {
  Host:"http://127.0.0.1",
}

在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 './routers/index';
import settings from "./settings"
// Vue.config.productionTip = false;
Vue.prototype.$settings = settings;
//
// /* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });


5.5 引入ElementUI
npm i element-ui -S
上面的命令等同于
npm install element-ui --save
执行命令效果:


5.5.1 配置ElementUI到项目中
在main.js中导入ElementUI,并调用。
代码:
// 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 './routers/index';
// 开发配置文件
// import settings from "./settings"
// Vue.prototype.$settings = settings;
// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件

Vue.use(ElementUI);
// Vue.config.productionTip = false;
/* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });


效果:

成功引入了ElementUI以后,接下来我们就可以开始进入前端页面开发,首先是首页。
接下来我们把之前完成的首页,直接拿过来使用[注意除了组件以外,还有静态文件也需要拿过来,包括App.vue里面的公共样式],并运行项目。
App.vue,全局css初始化代码
<style>
  body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}
</style>

Home.vue中添加代码:
<template>
  <div id="home">
    <Header/>
    <Banner/>
    <Footer/>
  </div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default {
name:"Home",

data(){
return {
}

},
components:{

Header,

Banner,

Footer,

}

}
</script>
<style scoped>
</style>

components/common/Header.vue
<template>
  <div class="header">
    <el-container>
      <el-header>
        <el-row>
          <el-col class="logo" :span="3">
            <a href="/">
              <img src="@/assets/head-logo.svg" alt="">
            </a>
          </el-col>
          <el-col class="nav" :span="16">
              <el-row>
                <el-col :span="3"><router-link class="current" to="/course">免费课</router-link></el-col>
                <el-col :span="3"><router-link to="/">轻课</router-link></el-col>
                <el-col :span="3"><router-link to="/">学位课</router-link></el-col>
                <el-col :span="3"><router-link to="/">题库</router-link></el-col>
                <el-col :span="3"><router-link to="/">教育</router-link></el-col>
              </el-row>
          </el-col>
          <el-col class="login-bar" :span="5">
            <el-row v-if="token">
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <b class="goods-number">0</b>
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
              <el-col class="member" :span="5">
                <el-menu class="el-menu-demo" mode="horizontal">
                  <el-submenu index="2">
                    <template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
                    <el-menu-item index="2-1">我的账户</el-menu-item>
                    <el-menu-item index="2-2">我的订单</el-menu-item>
                    <el-menu-item index="2-3">我的优惠卷</el-menu-item>
                    <el-menu-item index="2-3">退出登录</el-menu-item>
                  </el-submenu>
                </el-menu>
              </el-col>
            </el-row>
            <el-row v-else>
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col :span="10" :offset="5">
                <span class="register">
                  <router-link to="/login">登录</router-link>
                    |  
                  <router-link to="/register">注册</router-link>
                </span>
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </el-header>
    </el-container>
  </div>
</template>
<script>
export default {
name: "Header",

data(){
return {
// 设置一个登录标识,表示是否登录

token: false,

};

}

}
</script>
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;

}
.header .el-container{
width: 1200px;
margin: 0 auto;

}
.el-header{
height: 80px!important;
padding:0;

}
.logo{
}
.logo img{
padding-top: 22px;

}
.nav{
margin-top: 22px;

}
.nav .el-col a{
display: inline-block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
margin-left: 20px;

}
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;

}
.login-bar{
margin-top: 22px;

}
.cart-ico{
position: relative;
border-radius: 17px;

}
.cart-ico:hover{
background: #f0f0f0;

}
.goods-number{
width: 16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;

}
.cart-icon{
width: 15px;
height: auto;
margin-left: 6px;

}
.cart-ico span{
margin-left: 12px;

}
.member img{
width: 26px;
height: 26px;
border-radius: 50%;
display: inline-block;

}
.member img:hover{
border: 1px solid yellow;

}
</style>

components/common/Bannner.vue
<template>
  <div class="banner">
      <el-carousel trigger="click" height="473px">
        <el-carousel-item v-for="banner in banner_list">
          <a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
        </el-carousel-item>
      </el-carousel>
  </div>
</template>
<script>
export default {
name:"Banner",

data(){
return {
banner_list:[

{link:"http://www.baidu.com",img:"/static/banner/1.png"},

{link:"http://www.baidu.com",img:"/static/banner/2.png"},

{link:"http://www.baidu.com",img:"/static/banner/3.png"},

]

};

}

}
</script>
<style>
.el-carousel__arrow{
width: 100px!important;
height: 100px!important;

}
.el-icon-arrow-left{
font-size: 35px;
margin-left: 50px;

}
.el-carousel__arrow--left{
left: -50px;

}
</style>


components/common/Footer.vue
<template>
  <div class="footer">
    <el-container>
      <el-row>
        <el-col :span="4"><router-link to="">关于我们</router-link></el-col>
        <el-col :span="4"><router-link to="">联系我们</router-link></el-col>
        <el-col :span="4"><router-link to="">商务合作</router-link></el-col>
        <el-col :span="4"><router-link to="">帮助中心</router-link></el-col>
        <el-col :span="4"><router-link to="">意见反馈</router-link></el-col>
        <el-col :span="4"><router-link to="">新手指南</router-link></el-col>
        <el-col :span="24"><p class="copyright">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></el-col>
      </el-row>
    </el-container>
  </div>
</template>
<script>
export default {
name:"Footer",

data(){
return {}

}

}
</script>
<style scoped>
.footer{
width: 100%;
height: 128px;
background: #25292e;

}
.footer .el-container{
width: 1200px;
margin: auto;

}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
width: 100%;
margin-top: 38px;

}
.footer .el-row a{
color: #fff;
font-size: 14px;

}
.footer .el-row .copyright{
text-align: center;
color: #fff;
font-size: 14px;

}
</style>


也可以把App.vue的style标签的css代码放到static外部目录下引用过来
main.js
import "../static/css/reset.css";
reset.css
body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}



回到顶部(go to top)

6. 跨域CORS
我们现在为前端和后端分别设置两个不同的域名:


位置
域名



前端
 
www.luffycity.cn
 


后端
 
api.luffycity.cn
 



编辑/etc/hosts文件,可以设置本地域名
sudo vim /etc/hosts
在文件中增加两条信息
127.0.0.1   localhost
127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn

通过浏览器访问前端vue项目,会出现nginx的欢迎页面,主要因为我们当前项目已经有一个nginx监听了80端口,所以访问www.luffycity.cn网址时,会自动被转发到127.0.0.1本机,因为没有网址默认端口是80端口,所以被nginx进行处理了当前请求,因此我们暂时先把nginx关闭先。
# 查找nginx的进程
ps -ef|grep nginx
# 关闭进程
sudo kill -9 nginx进程号

关闭了nginx以后,访问www.luffy.cirty.cn网址,效果:

上面并不是错误,而是没人监听了这个地址和端口了,解决方法:
暂停运行前端项目,并修改配置文件config/index.js
    host: 'www.luffycity.cn', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,
保存修改信息,并重启项目

通过浏览器访问drf项目,会出现以下错误信息

可以通过settings/dev.py的ALLOWED_HOSTS,设置允许访问
# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.luffycity.cn',
]

让用户访问的时候,使用api.luffycity.cn:8000
1. 修改pycharm的manage.py的配置参数

现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持
否则前端无法使用axios无法请求后端提供的api数据,我们使用CORS来解决后端对跨域访问的支持。
使用django-cors-headers扩展
在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})
文档:https://github.com/ottoyiu/django-cors-headers/
安装
pip install django-cors-headers
添加应用
INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
中间层设置【必须写在第一个位置】
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]
添加白名单
# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'www.luffycity.cn:8080'
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie

完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。
前端使用 axios就可以访问到后端提供给的数据接口,但是如果要附带cookie信息,前端还要设置一下。
前端引入axios插件并配置允许axios发送cookie信息[axios本身也不允许ajax发送cookie到后端]
npm i axios -S

在main.js中引用 axios插件
import axios from 'axios'; // 从node_modules目录中导入包
// 允许ajax发送请求时附带cookie
axios.defaults.withCredentials = true;
Vue.prototype.$axios = axios; // 把对象挂载vue中




如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载!
<span >if</span> response <span >is</span> <span >None</span>:
    view = context[<span >'view'</span>]
    <span >if</span> isinstance(exc, DatabaseError):
        <span ># 数据库异常</span>
        logger.error(<span >'[%s] %s'</span> % (view, exc))
        response = Response({<span >'message'</span>: <span >'服务器内部错误'</span>}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

<span >return</span> response</code></pre>

REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
}
create database luffycity default charset=utf8;
create user luffy_user identified by 'luffy';
grant all privileges on luffycity.* to 'luffy_user'@'%';
flush privileges;
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "luffy_user",
        "PASSWORD": "luffy",
        "NAME": "luffycity",
    }
}
__init__.py
import pymysql

pymysql.install_as_MySQLdb()
cd 项目目录
vue init webpack lufei_pc
cd ~/Desktop
vue init webpack lufei_pc
npm run dev
npm i vue-router -S
import Vue from "vue"
import Router from "vue-router"
// 这里导入可以让让用户访问的组件
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#

mode: "history",
routes:[
// 路由列表

]

})

// 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 './routers/index';
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',

router,
components: { App },
template: '<App/>'

});

<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
export default {
name: 'App',
components: {
}

}
</script>
<style>

</style>

// import Vue from "vue"
// import Router from "vue-router"
//
//
// // 这里导入可以让让用户访问的组件
import Home from "../components/Home"
// Vue.use(Router);
//
// export default new Router({
//   // 设置路由模式为‘history’,去掉默认的#
//   mode: "history",
//   routes:[
//     // 路由列表
     {
       name:"Home",
       path:"/",
       component:Home,
     },
      {
       name:"Home",
       path:"/home",
       component:Home,
     },
   ]
// })

<template>
  <div id="home">
    前端首页
  </div>
</template>
<script>
  export default {
      name:"Home",
      data(){
          return {
      }
  }

}
</script>
<style scoped>

      }
  }

</style>

export default {
  Host:"http://127.0.0.1",
}

// // 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 './routers/index';
import settings from "./settings"
// Vue.config.productionTip = false;
Vue.prototype.$settings = settings;
//
// /* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });

npm i element-ui -S
npm install element-ui --save
// 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 './routers/index';
// 开发配置文件
// import settings from "./settings"
// Vue.prototype.$settings = settings;
// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件

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

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

<style>
  body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}

.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}
</style>
<template>
  <div id="home">
    <Header/>
    <Banner/>
    <Footer/>
  </div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default {
name:"Home",

data(){
return {
}

},
components:{

Header,

Banner,

Footer,

}

}
</script>
<style scoped>

}

</style>
<template>
  <div class="header">
    <el-container>
      <el-header>
        <el-row>
          <el-col class="logo" :span="3">
            <a href="/">
              <img src="@/assets/head-logo.svg" alt="">
            </a>
          </el-col>
          <el-col class="nav" :span="16">
              <el-row>
                <el-col :span="3"><router-link class="current" to="/course">免费课</router-link></el-col>
                <el-col :span="3"><router-link to="/">轻课</router-link></el-col>
                <el-col :span="3"><router-link to="/">学位课</router-link></el-col>
                <el-col :span="3"><router-link to="/">题库</router-link></el-col>
                <el-col :span="3"><router-link to="/">教育</router-link></el-col>
              </el-row>
          </el-col>
          <el-col class="login-bar" :span="5">
            <el-row v-if="token">
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <b class="goods-number">0</b>
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
              <el-col class="member" :span="5">
                <el-menu class="el-menu-demo" mode="horizontal">
                  <el-submenu index="2">
                    <template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
                    <el-menu-item index="2-1">我的账户</el-menu-item>
                    <el-menu-item index="2-2">我的订单</el-menu-item>
                    <el-menu-item index="2-3">我的优惠卷</el-menu-item>
                    <el-menu-item index="2-3">退出登录</el-menu-item>
                  </el-submenu>
                </el-menu>
              </el-col>
            </el-row>
            <el-row v-else>
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col :span="10" :offset="5">
                <span class="register">
                  <router-link to="/login">登录</router-link>
                    |  
                  <router-link to="/register">注册</router-link>
                </span>
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </el-header>
    </el-container>
  </div>
</template>
<script>
export default {
name: "Header",

data(){
return {
// 设置一个登录标识,表示是否登录

token: false,

};

}

}
</script>
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;

}
.header .el-container{
width: 1200px;
margin: 0 auto;

}
.el-header{
height: 80px!important;
padding:0;

}
.logo{
}
.logo img{
padding-top: 22px;

}
.nav{
margin-top: 22px;

}
.nav .el-col a{
display: inline-block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
margin-left: 20px;

}
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;

}
.login-bar{
margin-top: 22px;

}
.cart-ico{
position: relative;
border-radius: 17px;

}
.cart-ico:hover{
background: #f0f0f0;

}
.goods-number{
width: 16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;

}
.cart-icon{
width: 15px;
height: auto;
margin-left: 6px;

}
.cart-ico span{
margin-left: 12px;

}
.member img{
width: 26px;
height: 26px;
border-radius: 50%;
display: inline-block;

}
.member img:hover{
border: 1px solid yellow;

}

</style>
<template>
  <div class="banner">
      <el-carousel trigger="click" height="473px">
        <el-carousel-item v-for="banner in banner_list">
          <a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
        </el-carousel-item>
      </el-carousel>
  </div>
</template>
<script>
export default {
name:"Banner",

data(){
return {
banner_list:[

{link:"http://www.baidu.com",img:"/static/banner/1.png"},

{link:"http://www.baidu.com",img:"/static/banner/2.png"},

{link:"http://www.baidu.com",img:"/static/banner/3.png"},

]

};

}

}
</script>

<style>
.el-carousel__arrow{
width: 100px!important;
height: 100px!important;

}
.el-icon-arrow-left{
font-size: 35px;
margin-left: 50px;

}
.el-carousel__arrow--left{
left: -50px;

}
</style>

<template>
  <div class="footer">
    <el-container>
      <el-row>
        <el-col :span="4"><router-link to="">关于我们</router-link></el-col>
        <el-col :span="4"><router-link to="">联系我们</router-link></el-col>
        <el-col :span="4"><router-link to="">商务合作</router-link></el-col>
        <el-col :span="4"><router-link to="">帮助中心</router-link></el-col>
        <el-col :span="4"><router-link to="">意见反馈</router-link></el-col>
        <el-col :span="4"><router-link to="">新手指南</router-link></el-col>
        <el-col :span="24"><p class="copyright">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></el-col>
      </el-row>
    </el-container>
  </div>
</template>
<script>
export default {
name:"Footer",

data(){
return {}

}

}
</script>

<style scoped>
.footer{
width: 100%;
height: 128px;
background: #25292e;

}
.footer .el-container{
width: 1200px;
margin: auto;

}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
width: 100%;
margin-top: 38px;

}
.footer .el-row a{
color: #fff;
font-size: 14px;

}
.footer .el-row .copyright{
text-align: center;
color: #fff;
font-size: 14px;

}
</style>

import "../static/css/reset.css";
body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}

.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}

www.luffycity.cn
api.luffycity.cn
/etc/hosts
sudo vim /etc/hosts
127.0.0.1   localhost
127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn
# 查找nginx的进程
ps -ef|grep nginx
# 关闭进程
sudo kill -9 nginx进程号
    host: 'www.luffycity.cn', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,
# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.luffycity.cn',
]
1. 修改pycharm的manage.py的配置参数
在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})
pip install django-cors-headers
INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]
# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'www.luffycity.cn:8080'
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie
npm i axios -S
import axios from 'axios'; // 从node_modules目录中导入包
// 允许ajax发送请求时附带cookie
axios.defaults.withCredentials = true;

Vue.prototype.$axios = axios; // 把对象挂载vue中



    分类: 
            项目

<div >好文要顶
        关注我
    收藏该文
    
    
            
        
            panky
关注 - 8
粉丝 - 9
        
    
    
    +加关注0
    0
    
    
    
<div ></div>
<div >

<a href="" class="p_n_p_prefix">« </a> 上一篇:    <a href="" title="发布于 2019-07-31 21:30">Panky博客园目录</a>
<br>
<a href="" class="p_n_p_prefix">» </a> 下一篇:    <a href="" title="发布于 2019-08-04 22:35">luffy_01</a>




阅读目录(Content)

  • 1. Vue+Django+DRF项目搭建案例
  • 1.1 企业的web项目类型
  • 1.2 企业项目开发流程
  • 1.3 立项申请阶段
  • 2. 需求分析
  • 2.1 首页
  • 2.2 登录注册
  • 2.3 课程列表
  • 2.4 课程详情
  • 2.5 购物车
  • 2.6 商品结算
  • 2.7 购买成功
  • 2.8 个人中心
  • 2.9 视频播放
  • 3. 环境搭建
  • 3.1 创建虚拟环境
  • 3.2 相关命令复习
  • 3.3 依赖包安装
  • 4. 搭建项目
  • 4.1 创建项目
  • 4.3 打开项目
  • 4.2 调整目录
    • 4.2.1 分不同环境进行项目配置
  • 4.3 创建代码版本
    • 4.3.1 配置用户名和邮箱
  • 4.4 在git平台创建工程
  • 4.5 日志配置
  • 4.6 异常处理
  • 4.7 创建数据库
  • 4.8 配置数据库连接
  • 5. 搭建前端项目
  • 5.1 创建项目目录
  • 5.2 初始化前端项目
  • 5.3 安装路由vue-router
    • 5.3.1 下载路由组件
    • 5.3.2 配置路由
  • 5.4 前端初始化全局变量和全局方法
  • 5.5 引入ElementUI
    • 5.5.1 配置ElementUI到项目中
  • 6. 跨域CORS


回到顶部(go to top)

1. Vue+Django+DRF项目搭建案例


1.1 企业的web项目类型

  1. 商城
    1.1 B2C 直销商城 商家与会员直接交易 ( Business To Customer )
    1.2 B2B 批发商城 商家与商家直接交易
    1.3 B2B2C 购物平台 商家和会员在另一个商家提供的平台上面进行交易
    1.4 C2B 定制商城 会员向商家发起定制商品的需求,商家去完成。
    1.5 O2O 线上线下交易平台
    1.6 C2C 二手交易平台
  2. 门户网站[企业站和门户站]
  3. 社交网络
  4. 资讯论坛
  5. 内部系统
  6. 个人博客
  7. 内容收费站


1.2 企业项目开发流程

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM

自动化运维平台SysOM 自动化运维平台 vue+drf_git_02


1.3 立项申请阶段

立项其实就是对产品项目能不能做和怎么做,提出理论基础。大的互联网公司都有比较正规的立项流程。

自动化运维平台SysOM 自动化运维平台 vue+drf_git_03

通常公司内部要研发一款软硬件的产品之前,都要经过市场评估和调研分析,产生一份产品项目立项报告给公司。

产品项目立项报告一般包含以下内容:

项目概述
需求市场
需求分析和项目建设的必要性
业务分析
总体建设方案
项目风险和风险管理
可行性分析阶段

参考资料:

回到顶部(go to top)

2. 需求分析


2.1 首页

功能:导航菜单、轮播图、退出登录

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_04


2.2 登录注册

功能:用户登录、极验验证码、多条件登录、记住密码、短信发送、短信冷却倒计时、jwt认证

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_05

自动化运维平台SysOM 自动化运维平台 vue+drf_git_06


2.3 课程列表

功能:课程分类、课程列表、课程多条件筛选展示、课程分类展示、课程分页展示、课程章节课时展示、课程优惠策略

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_07


2.4 课程详情

功能:课程信息展示、视频播放、富文本编辑器

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_08


2.5 购物车

功能:购物车商品列表、添加商品、删除商品、勾选商品状态、商品结算、订单生成、唯一订单号生成

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_09


2.6 商品结算

功能:订单商品信息列表、订单信息展示、积分计算功能、优惠券策略、课程有效期计算、第三方支付平台接口

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_10


2.7 购买成功

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_11


2.8 个人中心

功能列表:我的订单、订单状态改变

自动化运维平台SysOM 自动化运维平台 vue+drf_git_12


2.9 视频播放

功能:视频加密播放

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_13

回到顶部(go to top)

3. 环境搭建


3.1 创建虚拟环境

mkvirtualenv luffy

如果自己的开发机子中存在多个版本的python,则可以指定解析器的版本

mkvirtualenv luffy -p python3

自动化运维平台SysOM 自动化运维平台 vue+drf_git_14


3.2 相关命令复习

创建虚拟环境:               mkvirtualenv 虚拟环境名称
创建虚拟环境(指定python版本): mkvirtualenv -p python3 虚拟环境名称
查看所有虚拟环境:            workon+2次tab键
使用虚拟环境:               workon 虚拟环境名称
退出虚拟环境:               deactivate
删除虚拟环境(必须先退出虚拟环境内部才能删除当前虚拟环境):
                            rmvirtualenv 虚拟环境名称

其他相关命令:

查看虚拟环境中安装的包:              pip freeze  或者 pip list

收集当前环境中安装的包及其版本:       pip freeze > requirements.txt

在部署项目的服务器中安装项目使用的模块: pip install -r requirements.txt

提示:

  • 虚拟环境只会管理环境内部的模块和python解析器,对于源代码是毫无关系
  • 创建虚拟环境需要联网
  • 创建成功后, 会自动工作在这个虚拟环境上
  • 工作在虚拟环境上, 提示符最前面会出现 “(虚拟环境名称)”


3.3 依赖包安装

pip install django
pip install djangorestframework
pip install PymySQL
pip install Pillow

pip install django-redis

回到顶部(go to top)

4. 搭建项目


4.1 创建项目

django-admin startproject luffy

效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_15


4.3 打开项目

在pycharm中打开项目

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_16

设置虚拟环境

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_17

自动化运维平台SysOM 自动化运维平台 vue+drf_git_18

启动django项目

use the manage.py not pycharm default start button

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_19

效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_20

提示:

在pycharm中如果要使用已经创建好的虚拟环境,则必须设置pycharm中的python解释器,设置为虚拟环境中的python。


4.2 调整目录

├── docs/          # 项目相关资料保存目录
├── logs/          # 项目运行时/开发时日志目录
├── manage.py
├── luffy/         # 项目主应用,开发时的代码保存
│   ├── apps/      # 开发者的代码保存目录,以模块[子应用]为目录保存
│   ├── libs/      # 第三方类库的保存目录[第三方组件、模块]
│   ├── settings/
│       ├── dev.py   # 项目开发时的本地配置
│       ├── prop.py  # 项目上线时的运行配置
│   ├── urls.py    # 总路由
│   ├── utils/     # 多个模块[子应用]的公共函数类库[自己开发的组件]
└── scripts/       # 保存项目运营时的脚本文件

自动化运维平台SysOM 自动化运维平台 vue+drf_git_21


4.2.1 分不同环境进行项目配置

开发者本地的环境、目录、数据库密码和线上的服务器都会不一样,所以我们的配置文件可以针对不同的系统分成多分.

  1. 在项目主应用下,创建一个settings的配置文件存储目录
  2. 根据线上线下两种情况分别创建2个配置文件 dev.py和prod.py
  3. 把原来项目主应用的 settings.py配置内容复制2份到dev.py和prod.py里面
  4. 把原来的settings.py配置文件修改文件名或者删除

新的目录settings:

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_22

接下来,就可以根据在manage.py中根据不同的情况导入对应的配置文件了.

自动化运维平台SysOM 自动化运维平台 vue+drf_git_23


4.3 创建代码版本

cd进入到自己希望存储代码的目录路径,并创建本地仓库.git【pycharm直接打开终端就是项目根目录了。无须cd了】
新创建的本地仓库.git是个空仓库

cd 目录路径
git init


4.3.1 配置用户名和邮箱

git config --global user.name 'lisi'
git config --global user.email 'lisi@163.com'


4.4 在git平台创建工程

公司一般都会有自己的代码仓库,一般都是自己搭建,也有使用第三方提供代码管理平台。

常用的代码管理平台:github、gitee(码云)

如果公司自己搭建的代码管理平台,gitlab框架

1) 创建私有项目库

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_24

自动化运维平台SysOM 自动化运维平台 vue+drf_自动化运维平台SysOM_25

创建私有空仓库以后的界面:

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_26

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_27

2)克隆项目到本地

注意:
    我们当前项目不需要这个步骤
    这个步骤是 当以后我们进入公司里面,参与人家已经在做的项目时,别人已经有仓库了,但是我们是新人加入项目中的,那么我们不需要在自己本地进行git init,直接git clone 复制别人的仓库代码
git clone 仓库地址
注意,如果当前目录下出现git仓库同名目录时,会克隆失败。

自动化运维平台SysOM 自动化运维平台 vue+drf_虚拟环境_28

3)创建并切换分支到dev

# git branch dev      # 创建本地分支dev,dev是自定义
# git checkout dev    # 切换本地分支代码
git checkout -b dev   # 这里是上面两句代码的简写

git提交

git add 代码目录   # 添加代码到上传队列
git status        # 查看当前项目的版本状态
git commit -m '添加项目代码'  # 提交代码到本地仓库, -m 表示本次提交的描述

推送到远端

git push origin dev:dev

如果推送代码,出现以下提示: git pull ....,则表示当前本地的代码和线上的代码版本不同.

1. 把线上的代码执行以下命令,拉取到本地,进行同步
git pull

2. 根据提示,移除多余的冲突的文件,也可以删除.

完成这些步骤以后,再次add,commit,push即可.

接下来,我们就把上面创建好的本地项目提交到gitee码云上面

# .表示当前目录下所有的文件或目录提交到上传队列[上传队列也叫"暂存区"]
git add .
# 把本地上传队列的代码提交到本地仓库

git commit -m "项目初始化搭建"
# 给本地的git版本控制软件设置项目的远程仓库地址

git remote add origin https://gitee.com/mooluo/luffyproject.git

# 提交代码给远程仓库

git push -u origin master
扩展:
1. 通过 git status 可以查看当前项目的代码版本状态
2. 通过 git reflog 可以查看代码版本日志[简单格式]
3. 通过 git log    可以查看代码版本日志[详细格式]

最终,成功提交了代码版本到gitee平台。效果:

自动化运维平台SysOM 自动化运维平台 vue+drf_git_29

上面虽然成功移交了代码版本,但是一些不需要的文件也被提交上去了。

所以,我们针对一些不需要的文件,可以选择从代码版本中删除,并且使用.gitignore把这些垃圾文件过滤掉。

git rm 文件  # 删除单个文件
git rm -rf 目录  # 递归删除目录

# 以下操作建议通过ubuntu的终端来完成,不要使用pycharm提供,否则删除.idea还会继续生成。

git rm -rf .idea

git rm db.sqlite3
# 注意,上面的操作只是从项目的源代码中删除,但是git是不知情的,所以我们需要同步。

git add .

git commit -m "删除不必要的文件或目录"

git push -u origin master

使用.gitignore把一些垃圾文件过滤掉。

vim .gitignore

./idea

./idea/*

./git

./db.sqlite3

开发时我们经常会使用pycharm的提供的git管理工具来完成代码的拉取和推送。

自动化运维平台SysOM 自动化运维平台 vue+drf_Vue_30


4.5 日志配置

在settings/dev.py文件中追加如下配置:

# 日志配置
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志位置,日志文件名,日志保存目录必须手动创建
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs/luffy.log"),
            # 日志文件的最大值,这里我们设置300M
            'maxBytes': 300 * 1024 * 1024,
            # 日志文件的数量,设置最大日志数量为10
            'backupCount': 10,
            # 日志格式:详细格式
            'formatter': 'verbose'
        },
    },
    # 日志对象
    'loggers': {
        'luffy': {
            'handlers': ['console', 'file'],
            'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}


4.6 异常处理

新建utils/exceptions.py

from rest_framework.views import exception_handler
from django.db import DatabaseError
from rest_framework.response import Response
from rest_framework import status
import logging

logger = logging.getLogger('luffy')
def custom_exception_handler(exc, context):
"""

自定义异常处理

:param exc: 异常类

:param context: 抛出异常的上下文

:return: Response响应对象

"""
# 调用drf框架原生的异常处理方法

response = exception_handler(exc, context)
<span >if</span> response <span >is</span> <span >None</span>:
    view = context[<span >'view'</span>]
    <span >if</span> isinstance(exc, DatabaseError):
        <span ># 数据库异常</span>
        logger.error(<span >'[%s] %s'</span> % (view, exc))
        response = Response({<span >'message'</span>: <span >'服务器内部错误'</span>}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

<span >return</span> response</code></pre>

settings/dev.py配置文件中添加
REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
}

4.7 创建数据库
create database luffycity default charset=utf8;

为当前项目创建数据库用户[这个用户只能看到这个数据库]
create user luffy_user identified by 'luffy';
grant all privileges on luffycity.* to 'luffy_user'@'%';
flush privileges;


4.8 配置数据库连接
打开settings/dev.py文件,并配置
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "luffy_user",
        "PASSWORD": "luffy",
        "NAME": "luffycity",
    }
}
在项目主模块的 __init__.py中导入pymysql
import pymysql
pymysql.install_as_MySQLdb()

调整错误
数据库版本检测导致的错误

数据库的版本检测代码注释掉。、

第二个错误也是因为数据库版本的默认编码导致,query返回的内容格式使用有误。
新增一行代码,把query查询结果转换格式为 bytes类型


回到顶部(go to top)

5. 搭建前端项目

5.1 创建项目目录
cd 项目目录
vue init webpack lufei_pc
例如,我要把项目保存在~/Desktop桌面目录下,可以如下操作:
cd ~/Desktop
vue init webpack lufei_pc
根据需要在生成项目时,我们选择对应的选项, 效果:

根据上面的提示,我们已经把vue项目构建好了,运行测试服务器。

打开项目已经,在pycharm的终端下运行vue项目,查看效果。
npm run dev
接下来,我们根据终端上效果显示的对应地址来访问项目(如果有多个vue项目在运行,8080端口被占据了,服务器会自动改端口,所以根据自己实际在操作中看到的地址来访问。)
访问:http://localost:8080。效果:

我们也可以把我们的前端项目进行git源代码管理

5.2 初始化前端项目
清除默认的HelloWorld组件和APP.vue中的默认样式

接下来,我们可以查看效果了,一张白纸~


5.3 安装路由vue-router

5.3.1 下载路由组件
npm i vue-router -S
执行效果:


5.3.2 配置路由
5.3.2.1 初始化路由对象
在src目录下创建routers路由目录,在routers目录下创建index.js路由文件
index.js路由文件中,编写初始化路由对象的代码 .
import Vue from "vue"
import Router from "vue-router"
// 这里导入可以让让用户访问的组件
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#

mode: "history",
routes:[
// 路由列表
]

})



5.3.2.2 注册路由信息
打开main.js文件,把router对象注册到vue中.代码:
// 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 './routers/index';
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',

router,
components: { App },
template: '<App/>'

});



5.3.2.3 在视图中显示路由对应的内容
在App.vue组件中,添加显示路由对应的内容。

代码:
<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
export default {
name: 'App',
components: {
}

}
</script>
<style>
</style>


5.3.2.4 创建并提供前端首页的组件
routers/index.js
// import Vue from "vue"
// import Router from "vue-router"
//
//
// // 这里导入可以让让用户访问的组件
import Home from "../components/Home"
// Vue.use(Router);
//
// export default new Router({
//   // 设置路由模式为‘history’,去掉默认的#
//   mode: "history",
//   routes:[
//     // 路由列表
     {
       name:"Home",
       path:"/",
       component:Home,
     },
      {
       name:"Home",
       path:"/home",
       component:Home,
     },
   ]
// })

创建Home组件
components/Home.vue
<template>
  <div id="home">
    前端首页
  </div>
</template>
<script>
  export default {
      name:"Home",
      data(){
          return {
      }
  }

}
</script>
<style scoped>
</style>




5.4 前端初始化全局变量和全局方法
在src目录下创建settings.js站点开发配置文件:
export default {
  Host:"http://127.0.0.1",
}

在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 './routers/index';
import settings from "./settings"
// Vue.config.productionTip = false;
Vue.prototype.$settings = settings;
//
// /* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });


5.5 引入ElementUI
npm i element-ui -S
上面的命令等同于
npm install element-ui --save
执行命令效果:


5.5.1 配置ElementUI到项目中
在main.js中导入ElementUI,并调用。
代码:
// 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 './routers/index';
// 开发配置文件
// import settings from "./settings"
// Vue.prototype.$settings = settings;
// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件

Vue.use(ElementUI);
// Vue.config.productionTip = false;
/* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });


效果:

成功引入了ElementUI以后,接下来我们就可以开始进入前端页面开发,首先是首页。
接下来我们把之前完成的首页,直接拿过来使用[注意除了组件以外,还有静态文件也需要拿过来,包括App.vue里面的公共样式],并运行项目。
App.vue,全局css初始化代码
<style>
  body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}
</style>

Home.vue中添加代码:
<template>
  <div id="home">
    <Header/>
    <Banner/>
    <Footer/>
  </div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default {
name:"Home",

data(){
return {
}

},
components:{

Header,

Banner,

Footer,

}

}
</script>
<style scoped>
</style>

components/common/Header.vue
<template>
  <div class="header">
    <el-container>
      <el-header>
        <el-row>
          <el-col class="logo" :span="3">
            <a href="/">
              <img src="@/assets/head-logo.svg" alt="">
            </a>
          </el-col>
          <el-col class="nav" :span="16">
              <el-row>
                <el-col :span="3"><router-link class="current" to="/course">免费课</router-link></el-col>
                <el-col :span="3"><router-link to="/">轻课</router-link></el-col>
                <el-col :span="3"><router-link to="/">学位课</router-link></el-col>
                <el-col :span="3"><router-link to="/">题库</router-link></el-col>
                <el-col :span="3"><router-link to="/">教育</router-link></el-col>
              </el-row>
          </el-col>
          <el-col class="login-bar" :span="5">
            <el-row v-if="token">
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <b class="goods-number">0</b>
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
              <el-col class="member" :span="5">
                <el-menu class="el-menu-demo" mode="horizontal">
                  <el-submenu index="2">
                    <template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
                    <el-menu-item index="2-1">我的账户</el-menu-item>
                    <el-menu-item index="2-2">我的订单</el-menu-item>
                    <el-menu-item index="2-3">我的优惠卷</el-menu-item>
                    <el-menu-item index="2-3">退出登录</el-menu-item>
                  </el-submenu>
                </el-menu>
              </el-col>
            </el-row>
            <el-row v-else>
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col :span="10" :offset="5">
                <span class="register">
                  <router-link to="/login">登录</router-link>
                    |  
                  <router-link to="/register">注册</router-link>
                </span>
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </el-header>
    </el-container>
  </div>
</template>
<script>
export default {
name: "Header",

data(){
return {
// 设置一个登录标识,表示是否登录

token: false,

};

}

}
</script>
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;

}
.header .el-container{
width: 1200px;
margin: 0 auto;

}
.el-header{
height: 80px!important;
padding:0;

}
.logo{
}
.logo img{
padding-top: 22px;

}
.nav{
margin-top: 22px;

}
.nav .el-col a{
display: inline-block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
margin-left: 20px;

}
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;

}
.login-bar{
margin-top: 22px;

}
.cart-ico{
position: relative;
border-radius: 17px;

}
.cart-ico:hover{
background: #f0f0f0;

}
.goods-number{
width: 16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;

}
.cart-icon{
width: 15px;
height: auto;
margin-left: 6px;

}
.cart-ico span{
margin-left: 12px;

}
.member img{
width: 26px;
height: 26px;
border-radius: 50%;
display: inline-block;

}
.member img:hover{
border: 1px solid yellow;

}
</style>

components/common/Bannner.vue
<template>
  <div class="banner">
      <el-carousel trigger="click" height="473px">
        <el-carousel-item v-for="banner in banner_list">
          <a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
        </el-carousel-item>
      </el-carousel>
  </div>
</template>
<script>
export default {
name:"Banner",

data(){
return {
banner_list:[

{link:"http://www.baidu.com",img:"/static/banner/1.png"},

{link:"http://www.baidu.com",img:"/static/banner/2.png"},

{link:"http://www.baidu.com",img:"/static/banner/3.png"},

]

};

}

}
</script>
<style>
.el-carousel__arrow{
width: 100px!important;
height: 100px!important;

}
.el-icon-arrow-left{
font-size: 35px;
margin-left: 50px;

}
.el-carousel__arrow--left{
left: -50px;

}
</style>


components/common/Footer.vue
<template>
  <div class="footer">
    <el-container>
      <el-row>
        <el-col :span="4"><router-link to="">关于我们</router-link></el-col>
        <el-col :span="4"><router-link to="">联系我们</router-link></el-col>
        <el-col :span="4"><router-link to="">商务合作</router-link></el-col>
        <el-col :span="4"><router-link to="">帮助中心</router-link></el-col>
        <el-col :span="4"><router-link to="">意见反馈</router-link></el-col>
        <el-col :span="4"><router-link to="">新手指南</router-link></el-col>
        <el-col :span="24"><p class="copyright">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></el-col>
      </el-row>
    </el-container>
  </div>
</template>
<script>
export default {
name:"Footer",

data(){
return {}

}

}
</script>
<style scoped>
.footer{
width: 100%;
height: 128px;
background: #25292e;

}
.footer .el-container{
width: 1200px;
margin: auto;

}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
width: 100%;
margin-top: 38px;

}
.footer .el-row a{
color: #fff;
font-size: 14px;

}
.footer .el-row .copyright{
text-align: center;
color: #fff;
font-size: 14px;

}
</style>


也可以把App.vue的style标签的css代码放到static外部目录下引用过来
main.js
import "../static/css/reset.css";
reset.css
body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}
.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}



回到顶部(go to top)

6. 跨域CORS
我们现在为前端和后端分别设置两个不同的域名:


位置
域名



前端
 
www.luffycity.cn
 


后端
 
api.luffycity.cn
 



编辑/etc/hosts文件,可以设置本地域名
sudo vim /etc/hosts
在文件中增加两条信息
127.0.0.1   localhost
127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn

通过浏览器访问前端vue项目,会出现nginx的欢迎页面,主要因为我们当前项目已经有一个nginx监听了80端口,所以访问www.luffycity.cn网址时,会自动被转发到127.0.0.1本机,因为没有网址默认端口是80端口,所以被nginx进行处理了当前请求,因此我们暂时先把nginx关闭先。
# 查找nginx的进程
ps -ef|grep nginx
# 关闭进程
sudo kill -9 nginx进程号

关闭了nginx以后,访问www.luffy.cirty.cn网址,效果:

上面并不是错误,而是没人监听了这个地址和端口了,解决方法:
暂停运行前端项目,并修改配置文件config/index.js
    host: 'www.luffycity.cn', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,
保存修改信息,并重启项目

通过浏览器访问drf项目,会出现以下错误信息

可以通过settings/dev.py的ALLOWED_HOSTS,设置允许访问
# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.luffycity.cn',
]

让用户访问的时候,使用api.luffycity.cn:8000
1. 修改pycharm的manage.py的配置参数

现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持
否则前端无法使用axios无法请求后端提供的api数据,我们使用CORS来解决后端对跨域访问的支持。
使用django-cors-headers扩展
在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})
文档:https://github.com/ottoyiu/django-cors-headers/
安装
pip install django-cors-headers
添加应用
INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
中间层设置【必须写在第一个位置】
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]
添加白名单
# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'www.luffycity.cn:8080'
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie

完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。
前端使用 axios就可以访问到后端提供给的数据接口,但是如果要附带cookie信息,前端还要设置一下。
前端引入axios插件并配置允许axios发送cookie信息[axios本身也不允许ajax发送cookie到后端]
npm i axios -S

在main.js中引用 axios插件
import axios from 'axios'; // 从node_modules目录中导入包
// 允许ajax发送请求时附带cookie
axios.defaults.withCredentials = true;
Vue.prototype.$axios = axios; // 把对象挂载vue中




如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载!
<span >if</span> response <span >is</span> <span >None</span>:
    view = context[<span >'view'</span>]
    <span >if</span> isinstance(exc, DatabaseError):
        <span ># 数据库异常</span>
        logger.error(<span >'[%s] %s'</span> % (view, exc))
        response = Response({<span >'message'</span>: <span >'服务器内部错误'</span>}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

<span >return</span> response</code></pre>

REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
}
create database luffycity default charset=utf8;
create user luffy_user identified by 'luffy';
grant all privileges on luffycity.* to 'luffy_user'@'%';
flush privileges;
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "luffy_user",
        "PASSWORD": "luffy",
        "NAME": "luffycity",
    }
}
__init__.py
import pymysql

pymysql.install_as_MySQLdb()
cd 项目目录
vue init webpack lufei_pc
cd ~/Desktop
vue init webpack lufei_pc
npm run dev
npm i vue-router -S
import Vue from "vue"
import Router from "vue-router"
// 这里导入可以让让用户访问的组件
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#

mode: "history",
routes:[
// 路由列表

]

})

// 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 './routers/index';
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',

router,
components: { App },
template: '<App/>'

});

<template>
  <div id="app">
    <router-view/>
  </div>
</template>
<script>
export default {
name: 'App',
components: {
}

}
</script>
<style>

</style>

// import Vue from "vue"
// import Router from "vue-router"
//
//
// // 这里导入可以让让用户访问的组件
import Home from "../components/Home"
// Vue.use(Router);
//
// export default new Router({
//   // 设置路由模式为‘history’,去掉默认的#
//   mode: "history",
//   routes:[
//     // 路由列表
     {
       name:"Home",
       path:"/",
       component:Home,
     },
      {
       name:"Home",
       path:"/home",
       component:Home,
     },
   ]
// })

<template>
  <div id="home">
    前端首页
  </div>
</template>
<script>
  export default {
      name:"Home",
      data(){
          return {
      }
  }

}
</script>
<style scoped>

      }
  }

</style>

export default {
  Host:"http://127.0.0.1",
}

// // 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 './routers/index';
import settings from "./settings"
// Vue.config.productionTip = false;
Vue.prototype.$settings = settings;
//
// /* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });

npm i element-ui -S
npm install element-ui --save
// 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 './routers/index';
// 开发配置文件
// import settings from "./settings"
// Vue.prototype.$settings = settings;
// elementUI 导入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 调用插件

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

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

<style>
  body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}

.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}
</style>
<template>
  <div id="home">
    <Header/>
    <Banner/>
    <Footer/>
  </div>
</template>
<script>
import Header from "./common/Header"
import Banner from "./common/Banner"
import Footer from "./common/Footer"
export default {
name:"Home",

data(){
return {
}

},
components:{

Header,

Banner,

Footer,

}

}
</script>
<style scoped>

}

</style>
<template>
  <div class="header">
    <el-container>
      <el-header>
        <el-row>
          <el-col class="logo" :span="3">
            <a href="/">
              <img src="@/assets/head-logo.svg" alt="">
            </a>
          </el-col>
          <el-col class="nav" :span="16">
              <el-row>
                <el-col :span="3"><router-link class="current" to="/course">免费课</router-link></el-col>
                <el-col :span="3"><router-link to="/">轻课</router-link></el-col>
                <el-col :span="3"><router-link to="/">学位课</router-link></el-col>
                <el-col :span="3"><router-link to="/">题库</router-link></el-col>
                <el-col :span="3"><router-link to="/">教育</router-link></el-col>
              </el-row>
          </el-col>
          <el-col class="login-bar" :span="5">
            <el-row v-if="token">
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <b class="goods-number">0</b>
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col class="study" :span="8" :offset="2"><router-link to="">学习中心</router-link></el-col>
              <el-col class="member" :span="5">
                <el-menu class="el-menu-demo" mode="horizontal">
                  <el-submenu index="2">
                    <template slot="title"><router-link to=""><img src="@/assets/logo@2x.png" alt=""></router-link></template>
                    <el-menu-item index="2-1">我的账户</el-menu-item>
                    <el-menu-item index="2-2">我的订单</el-menu-item>
                    <el-menu-item index="2-3">我的优惠卷</el-menu-item>
                    <el-menu-item index="2-3">退出登录</el-menu-item>
                  </el-submenu>
                </el-menu>
              </el-col>
            </el-row>
            <el-row v-else>
              <el-col class="cart-ico" :span="9">
                <router-link to="">
                  <img class="cart-icon" src="@/assets/cart.svg" alt="">
                  <span><router-link to="/cart">购物车</router-link></span>
                </router-link>
              </el-col>
              <el-col :span="10" :offset="5">
                <span class="register">
                  <router-link to="/login">登录</router-link>
                    |  
                  <router-link to="/register">注册</router-link>
                </span>
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </el-header>
    </el-container>
  </div>
</template>
<script>
export default {
name: "Header",

data(){
return {
// 设置一个登录标识,表示是否登录

token: false,

};

}

}
</script>
<style scoped>
.header{
top:0;
left:0;
right:0;
margin: auto;
background-color: #fff;
height: 80px;
z-index: 1000;
position: fixed;
box-shadow: 0 0.5px 0.5px 0 #c9c9c9;

}
.header .el-container{
width: 1200px;
margin: 0 auto;

}
.el-header{
height: 80px!important;
padding:0;

}
.logo{
}
.logo img{
padding-top: 22px;

}
.nav{
margin-top: 22px;

}
.nav .el-col a{
display: inline-block;
text-align: center;
padding-bottom: 16px;
padding-left: 5px;
padding-right: 5px;
position: relative;
font-size: 16px;
margin-left: 20px;

}
.nav .el-col .current{
color: #4a4a4a;
border-bottom: 4px solid #ffc210;

}
.login-bar{
margin-top: 22px;

}
.cart-ico{
position: relative;
border-radius: 17px;

}
.cart-ico:hover{
background: #f0f0f0;

}
.goods-number{
width: 16px;
height: 16px;
line-height: 17px;
font-size: 12px;
color: #fff;
text-align: center;
background: #fa6240;
border-radius: 50%;
transform: scale(.8);
position: absolute;
left: 16px;
top: -1px;

}
.cart-icon{
width: 15px;
height: auto;
margin-left: 6px;

}
.cart-ico span{
margin-left: 12px;

}
.member img{
width: 26px;
height: 26px;
border-radius: 50%;
display: inline-block;

}
.member img:hover{
border: 1px solid yellow;

}

</style>
<template>
  <div class="banner">
      <el-carousel trigger="click" height="473px">
        <el-carousel-item v-for="banner in banner_list">
          <a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
        </el-carousel-item>
      </el-carousel>
  </div>
</template>
<script>
export default {
name:"Banner",

data(){
return {
banner_list:[

{link:"http://www.baidu.com",img:"/static/banner/1.png"},

{link:"http://www.baidu.com",img:"/static/banner/2.png"},

{link:"http://www.baidu.com",img:"/static/banner/3.png"},

]

};

}

}
</script>

<style>
.el-carousel__arrow{
width: 100px!important;
height: 100px!important;

}
.el-icon-arrow-left{
font-size: 35px;
margin-left: 50px;

}
.el-carousel__arrow--left{
left: -50px;

}
</style>

<template>
  <div class="footer">
    <el-container>
      <el-row>
        <el-col :span="4"><router-link to="">关于我们</router-link></el-col>
        <el-col :span="4"><router-link to="">联系我们</router-link></el-col>
        <el-col :span="4"><router-link to="">商务合作</router-link></el-col>
        <el-col :span="4"><router-link to="">帮助中心</router-link></el-col>
        <el-col :span="4"><router-link to="">意见反馈</router-link></el-col>
        <el-col :span="4"><router-link to="">新手指南</router-link></el-col>
        <el-col :span="24"><p class="copyright">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></el-col>
      </el-row>
    </el-container>
  </div>
</template>
<script>
export default {
name:"Footer",

data(){
return {}

}

}
</script>

<style scoped>
.footer{
width: 100%;
height: 128px;
background: #25292e;

}
.footer .el-container{
width: 1200px;
margin: auto;

}
.footer .el-row {
align-items: center;
padding: 0 200px;
padding-bottom: 15px;
width: 100%;
margin-top: 38px;

}
.footer .el-row a{
color: #fff;
font-size: 14px;

}
.footer .el-row .copyright{
text-align: center;
color: #fff;
font-size: 14px;

}
</style>

import "../static/css/reset.css";
body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
ul{
list-style: none;

}
img{
width: 100%;

}

.header .el-menu li .el-submenu__title{
height: 26px!important;
line-height: 26px!important;

}
.el-menu--popup{
min-width: 140px;

}
.el-checkbox__inner{
width:16px;
height: 16px;
border: 1px solid #999;

}
.el-checkbox__inner:after{
width: 6px;
height: 8px;

}
.el-form-item__content{
margin-left:0px!important;
width: 120px;

}

www.luffycity.cn
api.luffycity.cn
/etc/hosts
sudo vim /etc/hosts
127.0.0.1   localhost
127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn
# 查找nginx的进程
ps -ef|grep nginx
# 关闭进程
sudo kill -9 nginx进程号
    host: 'www.luffycity.cn', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,
# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.luffycity.cn',
]
1. 修改pycharm的manage.py的配置参数
在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})
pip install django-cors-headers
INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]
# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'www.luffycity.cn:8080'
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie
npm i axios -S
import axios from 'axios'; // 从node_modules目录中导入包
// 允许ajax发送请求时附带cookie
axios.defaults.withCredentials = true;

Vue.prototype.$axios = axios; // 把对象挂载vue中