• Vue+Django+DRF项目搭建案例


    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 企业项目开发流程

    开发流程

    img

    1.3 立项申请阶段

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

    20180601170947776

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

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

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

    参考资料:https://blog.csdn.net/m0_37370820/article/details/81077886

    2. 需求分析

    2.1 首页

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

    1555309744206

    2.2 登录注册

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

    1555309859755

    1555310015496

    2.3 课程列表

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

    1555311221819

    2.4 课程详情

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

    1555311433851

    2.5 购物车

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

    1555311588633

    2.6 商品结算

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

    1555311715736

    2.7 购买成功

    1553138273460

    2.8 个人中心

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

    1555312510196

    2.9 视频播放

    功能:视频加密播放

    1553137882937

    3. 环境搭建

    3.1 创建虚拟环境

    mkvirtualenv luffy
    

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

    mkvirtualenv luffy -p python3
    

    1557367438248

    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
    

    4. 搭建项目

    4.1 创建项目

    django-admin startproject luffy
    

    效果:

    1557367703530

    4.3 打开项目

    在pycharm中打开项目

    1557367755691

    设置虚拟环境

    1553139497155

    1557367856794

    启动django项目

    use the manage.py not pycharm default start button

    1557367925009

    效果:

    1557367991756

    提示:

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

    4.2 调整目录

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

    1557368526149

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

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

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

    新的目录settings:

    1557368720318

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

    1557368958823

    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) 创建私有项目库

    1557373432053

    1557373444325

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

    1557373625527

    1557373639755

    2)克隆项目到本地

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

    1557373835075

    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平台。效果:

    1557374414461

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

    所以,我们针对一些不需要的文件,可以选择从代码版本中删除,并且使用.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管理工具来完成代码的拉取和推送。

    1557375896356

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

    settings/dev.py配置文件中添加

    REST_FRAMEWORK = {
        # 异常处理
        'EXCEPTION_HANDLER': 'luffy.utils.exceptions.custom_exception_handler',
    }
    

    4.7 创建数据库

    create database luffycity default charset=utf8;
    

    1557450273503

    为当前项目创建数据库用户[这个用户只能看到这个数据库]

    create user luffy_user identified by 'luffy';
    grant all privileges on luffycity.* to 'luffy_user'@'%';
    flush privileges;
    

    1557450379001

    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()
    

    调整错误

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

    1557453985484

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

    1557454099123

    第二个错误也是因为数据库版本的默认编码导致,query返回的内容格式使用有误。

    新增一行代码,把query查询结果转换格式为 bytes类型

    1557454044879

    5. 搭建前端项目

    5.1 创建项目目录

    cd 项目目录
    vue init webpack lufei_pc
    

    例如,我要把项目保存在~/Desktop桌面目录下,可以如下操作:

    cd ~/Desktop
    vue init webpack lufei_pc
    

    根据需要在生成项目时,我们选择对应的选项, 效果:

    1557451009689

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

    1557451125218

    打开项目已经,在pycharm的终端下运行vue项目,查看效果。

    npm run dev
    

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

    访问:http://localost:8080。效果:

    1557451188340

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

    5.2 初始化前端项目

    清除默认的HelloWorld组件和APP.vue中的默认样式

    1557451289161

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

    1557451300406

    5.3 安装路由vue-router

    5.3.1 下载路由组件

    npm i vue-router -S
    

    执行效果:

    1557451350882

    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:[
        // 路由列表
    
      ]
    })
    
    

    1557451480681

    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/>'
    });
    
    

    1557451533378

    5.3.2.3 在视图中显示路由对应的内容

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

    1557451572377

    代码:

    <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>
    
    

    1557451775965

    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
    

    执行命令效果:

    1557452146253

    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/>'
    // });
    
    

    效果:

    1557452192638

    成功引入了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{
         100%;
      }
    
      .header .el-menu li .el-submenu__title{
        height: 26px!important;
        line-height: 26px!important;
      }
      .el-menu--popup{
        min- 140px;
      }
      .el-checkbox__inner{
        16px;
        height: 16px;
        border: 1px solid #999;
      }
      .el-checkbox__inner:after{
         6px;
        height: 8px;
      }
      .el-form-item__content{
        margin-left:0px!important;
         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>
                      &nbsp;&nbsp;|&nbsp;&nbsp;
                      <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{
         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{
         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{
         15px;
        height: auto;
        margin-left: 6px;
      }
      .cart-ico span{
        margin-left: 12px;
      }
      .member img{
         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{
       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{
       100%;
      height: 128px;
      background: #25292e;
    }
    .footer .el-container{
       1200px;
      margin: auto;
    }
    .footer .el-row {
      align-items: center;
      padding: 0 200px;
      padding-bottom: 15px;
       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{
         100%;
      }
    
      .header .el-menu li .el-submenu__title{
        height: 26px!important;
        line-height: 26px!important;
      }
      .el-menu--popup{
        min- 140px;
      }
      .el-checkbox__inner{
        16px;
        height: 16px;
        border: 1px solid #999;
      }
      .el-checkbox__inner:after{
         6px;
        height: 8px;
      }
      .el-form-item__content{
        margin-left:0px!important;
         120px;
      }
    
    

    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
    

    1557454299594

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

    # 查找nginx的进程
    ps -ef|grep nginx
    # 关闭进程
    sudo kill -9 nginx进程号
    

    1557454528245

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

    1557454604654

    上面并不是错误,而是没人监听了这个地址和端口了,解决方法:

    暂停运行前端项目,并修改配置文件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,
    

    保存修改信息,并重启项目

    1557454684623

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

    1557454965635

    可以通过settings/dev.py的ALLOWED_HOSTS,设置允许访问

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

    1557455086164

    让用户访问的时候,使用api.luffycity.cn:8000

    1. 修改pycharm的manage.py的配置参数
    

    1557455152863

    现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持

    否则前端无法使用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
    

    1557455675163

    完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。

    前端使用 axios就可以访问到后端提供给的数据接口,但是如果要附带cookie信息,前端还要设置一下。

    前端引入axios插件并配置允许axios发送cookie信息[axios本身也不允许ajax发送cookie到后端]

    npm i axios -S
    

    1557455747921

    在main.js中引用 axios插件

    import axios from 'axios'; // 从node_modules目录中导入包
    // 允许ajax发送请求时附带cookie
    axios.defaults.withCredentials = true;
    
    Vue.prototype.$axios = axios; // 把对象挂载vue中
    
  • 相关阅读:
    openVolumeMesh example 程序学习
    使用字符串创建java 对象
    HDU-1501-Zipper
    UVA-10285-Longest Run on a Snowboard
    HDU-2182-Frog
    HDU-2044-一只小蜜蜂
    POJ-1163-The Triangle
    HDU-1159-Common Subsequence
    HDU-2069-Coin Change
    HDU-4864-Task
  • 原文地址:https://www.cnblogs.com/pankypan/p/11279246.html
Copyright © 2020-2023  润新知