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

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

2)克隆项目到本地

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

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

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

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

4.6 日志配置

在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"),
            'maxBytes': 300 * 1024 * 1024,
            'backupCount': 10,
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'propagate': True,
        },
    }
}

4.5 异常处理

新建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.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()

5. 搭建前端项目

5.1 创建项目目录

cd 项目目录
vue init webpack lufei_pc

例如,我要把项目保存在D:/moluo的根目录下,可以如下操作:

D:
cd /moluo
vue init webpack lufei_pc

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

根据上面的提示,我们已经把vue项目构建好了,接下来我们可以在pycharm编辑器中把项目打开并根据上面黄色提示,运行测试服务器。

打开项目已经,在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:[
    // 路由列表

  ]
})

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

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

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

代码:

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {

  }
}
</script>

<style>

</style>

创建并提供前端首页的组件

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,
     }
   ]
// })

创建Home组件

components/Home.vue

<template>
  <div class="home">
    前端首页
  </div>
</template>
<script>
  export default {
    name:"Home"
  }
</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>
.el-checkbox__inner{
  border: 1px solid #9b9b9b;
  border-radius: 0;
  width: 16px;
  height: 16px;
}
.el-checkbox__inner::after{
  height: 8px;
  width: 6px;
}
</style>

Home.vue中添加代码:

<template>
  <div class="home">
    <Header :current_page="current_page"/>
    <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 {
        current_page:0,
      };
    },
    components:{
      Header,
      Banner,
      Footer,
    }
  }
</script>

<style scoped>
.home{
  padding-top: 80px;
}
</style>

components/common/Header.vue

<template>
  <div class="header">
    <el-container>
      <el-header height="80px">
         <el-row>
           <el-col class="logo" :span="3">
             <router-link to="/"><img src="../../assets/head-logo.svg" alt=""></router-link>
           </el-col>
           <el-col :span="16">
             <!-- gutter每一列之间的间隔空隙 -->
             <el-row class="nav" :gutter="20">
                <el-col :span="3"><router-link :class="current_page==1?'active':''" to="/courses">免费课</router-link></el-col>
                <el-col :span="3"><router-link :class="current_page==2?'active':''" to="/courses">轻课</router-link></el-col>
                <el-col :span="3"><router-link :class="current_page==3?'active':''" to="/courses">学位课</router-link></el-col>
                <el-col :span="3"><router-link :class="current_page==4?'active':''" to="/courses">题库</router-link></el-col>
                <el-col :span="3"><router-link :class="current_page==5?'active':''" to="/courses">教育</router-link></el-col>
              </el-row>
           </el-col>
           <el-col v-if="is_login" class="login-bar" :span="5">
             <div class="cart-ico">
                 <b></b>
                 <img src="../../assets/cart.svg" alt="">
               <span>购物车</span>
             </div>
             <div class="study">学习中心</div>
             <div class="member">
               <el-dropdown>
                  <span class="el-dropdown-link">
                    <img src="../../assets/logo@2x.png" alt="">
                  </span>
                  <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
                    <el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
                    <el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
                    <el-dropdown-item>我的账户 <i class="el-icon-arrow-right"></i></el-dropdown-item>
                  </el-dropdown-menu>
                </el-dropdown>
             </div>
           </el-col>
           <el-col v-else class="login-bar" :span="5">
             <div class="cart-ico">
                 <img src="../../assets/cart.svg" alt="">
               <span>购物车</span>
             </div>
             <span class="header-login">登录</span>
             &nbsp;&nbsp;|&nbsp;&nbsp;
             <span class="header-register">注册</span>
           </el-col>
         </el-row>
      </el-header>
    </el-container>
  </div>
</template>

<script>
  export default {
    name:"Header",
    props:["current_page"],
    data(){
      return {
        is_login: false, /* 是否登录 */
      }
    }
  }
</script>

<style scoped>
.header{
    width: 100%;
    height: 80px;
    background: #fff;
    position: fixed;
    left: 0;
    top: 0;
    margin: 0 auto;
    z-index: 7;
    text-overflow: ellipsis;
    white-space: nowrap;
    box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
}
.el-container{
  width: 1200px;
  margin: 0 auto;
}
.el-header{
  padding: 0;
}
.el-row,.el-col{
  height: 80px;
}
.logo{
  width: 118px;
}
.logo,.nav{
    line-height: 80px;
}
.logo img{
   vertical-align: middle; /* 设置图片垂直居中 */
}
.nav{
  margin-left: 30px!important;
  margin-right: 0!important;
}
.nav .el-col .active{
  padding-bottom: 16px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom: 4px solid #ffc210;
}
.nav,.study{
  text-align: center;
  color: #4a4a4a;
}
.nav .el-col:hover,.nav .el-col a:hover,.study:hover,.study a:hover{
  color: #000000;
}
.login-bar{
  display: flex;
  align-items: center;
}
.cart-ico{
    width: 88px;
    height: 28px;
    margin-right: 20px;
    background: #f7f7f7;
    border-radius: 17px;
    display: flex;
    align-items: center;
    justify-content: space-around;
    cursor: pointer;
    position: relative;
    font-size: 14px;
}
.cart-ico b{
    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-ico img{
    width: 15px;
    height: auto;
    margin-left: 6px;
}
.cart-ico span{
    margin-right: 6px;
}
.study{
    padding-left: 0;
    font-family: PingFangSC-Regular;
    letter-spacing: 0;
    margin-right: 20px;
    font-size: 15px;
    cursor: pointer;
}
.member img{
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: inline-block;
    cursor: pointer;
    vertical-align: middle;
}
.member img:hover{
    border: 1px solid rgb(255, 194, 16);
}
.el-dropdown-menu{
  left: 1130px!important;
  width: 180px;
  top: 64px!important;
}
.el-dropdown-menu i{
  float:right;
  line-height: 36px;
}
.header-login,.header-register{
  cursor: pointer;
  font-size: 15px;
  color: #4a4a4a;
}
.header-login:hover,.header-register:hover{
  color: #000000;
}
</style>

components/common/Bannner.vue

<template>
  <div class="banner">
      <el-carousel trigger="click" height="506px">
      <el-carousel-item v-for="item in banner_list">
        <img :src="item" alt="">
      </el-carousel-item>
    </el-carousel>
  </div>
</template>

<script>
  export default {
    name:"Banner",
    data(){
      return {
        banner_list:[
          "/static/banner/1.jpeg",
          "/static/banner/2.png",
          "/static/banner/3.png",
          "/static/banner/4.png",
          "/static/banner/5.png",
          "/static/banner/6.png",
        ]
      };
    }
  }
</script>

<style scoped>
.banner img{
  width: 100%;
}
</style>

components/common/Footer.vue

<template>
  <el-container>
      <el-footer height="128px">
          <el-row>
            <el-col :span="4">关于我们</el-col>
            <el-col :span="4">联系我们</el-col>
            <el-col :span="4">商务合作</el-col>
            <el-col :span="4">帮助中心</el-col>
            <el-col :span="4">意见反馈</el-col>
            <el-col :span="4">新手指南</el-col>
          </el-row>
        <el-row class="copyright">
          <el-col :span="24">Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</el-col>
        </el-row>
      </el-footer>
  </el-container>
</template>

<script>
  export default {
    name:"Footer",
    data(){
      return {}
    }
  }
</script>


<style scoped>
.el-footer {
  font-size: 14px;
  padding-top: 40px;
  background-color: #25292e;
  color: #fff;
}
.el-row{
  width: 1200px;
  margin: 0 auto;
  padding: 0 260px;
}
.copyright{
  padding-top: 15px;
  text-align: center;
}
</style>

也可以把App.vue的style标签的css代码放到static外部目录下引用过来

main.js

import "../static/css/reset.css";

reset.css

body,p,ul,li,h1,h2,h3,h4,form,input,select{
  margin:0;
  padding:0;
}
ul,li{
  list-style: none;
}
a{
  color: #4a4a4a;
  text-decoration: none;
}
img{
  width: 100%;
}

并添加对应在src/assetc和static目录下图片

6. 跨域CORS

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

前端www.luffycity.cn
后端api.luffycity.cn

编辑/etc/hosts文件,可以设置本地域名

在文件中增加两条信息

127.0.0.1   localhost
127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn

通过浏览器访问前端vue项目,会出现以下错误:

解决方法:

暂停运行前端项目,并修改配置文件config/index.js

    host: 'www.luffycity.cn', // can be overwritten by process.env.HOST
    port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined

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

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

可以通过settings的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:80'
)
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中
12-14 06:06
查看更多