项目搭建


后台项目创建和目录调整

 

# 第三步,调整目录
    #### 调整配置文件
    -把配置文件移动到setting文件夹下了,改名为dev.py,又新建了一个pro.py
    -dev.py:开发阶段用的配置
    -pro.py:上线阶段用的配置
    -manage.py 中指向的配置文件,改成咱么修改后路径
    -控制台:python manage.py runserver  或者点绿色箭头就可以启动项目了
      
  ### 调整app的路径,以后把所有app都放到luffy_api下的apps文件夹---》整洁
      -切换到apps路径下,执行创建app的命令
        -python ../../manage.py startapp user
        -在dev.py中注册app,运行报错,报错原因是找不到user这么模块
    -原来直接写app名字不报错--》原因是app就在项目根路径下(模块的查找)--》由于项目的根路径在环境变量中,app就在根路径下,它能直接找到
    -现在的问题是apps路径不在环境变量中,它就找不到
    -把apps的路径加入到环境变量中--》要在项目的启动时加--》启动入口是配置文件
        -到配置文件中:写入  sys.path.append(os.path.join(BASE_DIR,'apps'))
    -以后再INSTALLED_APPS中只需要写app的名字即可
    
    
#### 新建 logs文件夹,luffy_api/lib文件夹,luffy_api/utils文件夹,script文件夹


### 测试阶段运行没问题,项目上线,使用uwsgi上线---》运行wsgi.py-->修改如下
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.setting.pro')

### 国际化
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False

## 把 小luffy_api也就是BASE_DIR 也加入到环境变量
sys.path.append(BASE_DIR)
导入模块的时候,只要从环境变量的路径开始导就可以了,从小luffy_api路径开始导入即可
但是pycharm爆红,但是没有错,点右键,把该路径(在环境变量中的),做成source root即可
以后再从这个路径下导包,不会报错了
### 注意:以后导入包
    -尽量用最短路径导入,如果从长路径导入--》路径经过的py文件都会去执行--》可能会导致循环导入的问题
  -我个人推荐用相对导入
  # from apps.user import models
    from . import models  推荐用这个
  
  -py文件中有相对导入,这个py文件不能作为脚本运行
      -django项目中,由于没有右键运行的脚本,所以都可以用相对导入

### 项目目录结构
"""
├── luffy_api
    ├── logs/                      # 项目运行时/开发时日志目录 - 包
  ├── luffy_api/      # 项目主应用,开发时的代码保存 - 包
         ├── apps/              # 开发者的代码保存目录,以模块[子应用]为目录保存 - 包
      ├── libs/              # 第三方类库的保存目录[第三方组件、模块] - 包
        ├── setting/          # 配置目录 - 包
                ├── dev.py        # 项目开发时的本地配置
                └── prod.py       # 项目上线时的运行配置
          ├── urls.py             # 总路由
          └── utils/              # 多个模块[子应用]的公共函数类库[自己开发的组件]
    ├── manage.py               # 脚本文件
  └── scripts/           # 保存项目运营时的脚本文件 - 文件夹
"""
         

后台配置

配置日志

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': {
            # 实际开发建议使用WARNING
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {
            # 实际开发建议使用ERROR
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
            # 日志文件的最大值,这里我们设置300M
            'maxBytes': 300 * 1024 * 1024,
            # 日志文件的数量,设置最大日志数量为10
            'backupCount': 10,
            # 日志格式:详细格式
            'formatter': 'verbose',
            # 文件内容编码
            'encoding': 'utf-8'
        },
    },
    # 日志对象
    'loggers': {
        'django': {
            'handlers': ['console', 'file'],
            'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}


### 在utils下简历logging.py
import logging
# 创造一个logger对象,使用的是配置文件中的django这个
logger = logging.getLogger('django')


## 以后使用,导入直接用--》打印到控制台和记录到文件中
from utils.logging import logger
logger.info("我执行了一下")

处理全局异常

## 全局异常捕获

from rest_framework.views import exception_handler  # 默认没有配置,出了异常会走它
from rest_framework.response import Response
from utils.logging import logger

def common_exception_handler(exc, context):
    res = exception_handler(exc, context)
    if res:
        res = Response(data={'code': 998, 'msg': res.data.get('detail', '服务器异常,请联系系统管理员')})
    else:
        res = Response(data={'code': 999, 'msg': str(exc)})
    request = context.get('request')
    view = context.get('view')
    logger.error('错误原因:%s,错误视图类:%s,请求地址:%s,请求方式:%s' % (str(exc), str(view), request.path, request.method))
    return res

配置文件中配置

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'utils.exception.common_exception_handler'  # 再出异常,会执行这个函数
}

二次封装Response

创建一个py文件,继承Response

from rest_framework.response import Response


class ApiResponse(Response):
    def __init__(self, status=100, msg='成功', http_status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None, **kwargs):
        data = {
            'status': status,
            'msg': msg
        }
        if kwargs:
            data.update(kwargs)
        super().__init__(data=data, status=http_status,
                         template_name=template_name, headers=headers,
                         exception=exception, content_type=content_type)

后台数据库配置

# 使用mysql---》创建一个库(手动)--》库名:luffy
# 项目配置文件中,连接这个数据库


### 创建数据库,并配置
-create database luffy default charset=utf8;
### 给数据库创建一个lqz用户,它只能操作luffy库---》万一你的lqz用户密码泄露了--》
# 查看用户
# 5.7之前版本
select user,host,password from mysql.user;
# 5.7往后的版本
select user,host,authentication_string from mysql.user;

## 创建用户
# 授权账号命令:grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'
grant all privileges on luffy.* to 'lqz'@'%' identified by 'Luffy123?';
grant all privileges on luffy.* to 'lqz'@'localhost' identified by 'Luffy123?';
grant all privileges on luffy.* to 'xk'@'%' identified by 'Luffy123?';
grant all privileges on luffy.* to 'xk'@'localhost' identified by 'Luffy123?';
# mysql -h 127.0.0.1 -P 3306 -uroot -p
# mysql -uroot -p     有区别,如果在本地连接,使用这个,速度会快

# 刷新权限
flush privileges;


## 项目配置文件加入
   'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'luffy', # 数据库名字
        'USER': 'lqz', # 用户名
        'PASSWORD': 'Luffy123?',
        'HOST': 'localhost',
        'PORT': 3306
    }
    
    
### django操作mysql
    -模式使用MysqlDB来操作---》MysqlDB在python3.x以后不存在了
  -使用pymysql替换---》django2.0.7版本及以上,如果使用pymysql替换,需要改django源码
  
### 关于pymysql和mysqlclient的选择
  # 这两句话,只要执行即可,放在那里都行---》只要django执行,所有py文件中顶格写的代码都会执行
  # 作用是?猴子补丁,动态替换  --->python一切皆对象,可以动态替换对象
  # 如果该源码,后期只要使用django,都要改它的源码
  # 所以咱们换另一个操作mysql的模块,mysqlclient---》MysqlDB的3版本--》有可能装不上--》win上看人品,实在装不上用whl文件装 linux上有不同解决方案
  # http://www.liuqingzheng.top/python/%E5%85%B6%E4%BB%96/01-%E5%90%84%E4%B8%BB%E6%B5%81Linux%E7%B3%BB%E7%BB%9F%E8%A7%A3%E5%86%B3pip%E5%AE%89%E8%A3%85mysqlclient%E6%8A%A5%E9%94%99/
  # import pymysql
  # pymysql.install_as_MySQLdb()
  
#### 使用mysqlclient不需要写两句话,不用改源码

user模块user表设计

# 用户板块---》做成app
python ../../manage.py startapp user

# 创建用户表,基于auth的user表扩写
### 注意:在写好这个之前,不要先迁移数据,如果迁移了数据库,这个就不行了
### 如果你已经迁移了,删除数据库,删除所有的migrations文件,包含你自己的app,和auth和admin这两个app

## models.py
from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    mobile = models.CharField(max_length=11, unique=True)  # 唯一,长度11
    # 需要pillow包的支持 ImageField继承自FileField
    icon = models.ImageField(upload_to='icon', default='icon/default.png')

    class Meta:
        db_table = 'luffy_user'
        verbose_name = '用户表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username
      
      
 # 配置文件---》注册表
  INSTALLED_APPS = [
      # ...
      'user',
  ]

  # 自定义User表
  AUTH_USER_MODEL = 'user.User'
  
  
  ## 配置media
  MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')


  # 安装pillow ,迁移
  pip install pillow
  python manage.py makemigrations
  python manage.py migrate
  

前台创建及配置

# 创建项目
vue create luffycity
# 使用pycharm打开

# 删除一些东西
### APP.vue


## HomeView.vue




## router下的index.js 
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
]

### elementui ,bootstrap,jquery,axios配置
# axios
cnpm install axios  -S
## main.js
import axios from 'axios'
Vue.prototype.$axios = axios;

#elementui
cnpm install element-ui -S
## main.js
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

# bootstrap和jq
cnpm install jquery -S
cnpm install bootstrap@3 -S
## vue.config.js
module.exports = {
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "window.jQuery": "jquery",
                "window.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    }
};
## main.js
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'




### 全局css样式配置
##assets/css/global.css
/* 声明全局样式和项目的初始化样式 */
body, h1, h2, h3, h4, h5, h6, p, table, tr, td, ul, li, a, form, input, select, option, textarea {
    margin: 0;
    padding: 0;
    font-size: 15px;
}

a {
    text-decoration: none;
    color: #333;
}

ul {
    list-style: none;
}

table {
    border-collapse: collapse; /* 合并边框 */
}

## main.js
// 把自己定义的global.css 引入
import './assets/css/global.css'


## 配置文件配置
# assets/js/settings.js
export default {
    base_url: "http://127.0.0.1:8000"
}
# main.js 
// 把自己定义的global.css 引入
import './assets/css/global.css'
// 导入自定义配置
import settings from './assets/js/settings'
Vue.prototype.$settings = settings;

前台主页

Homeviwe.vue

 
<template>
    <div class="home">
        <Header>Header>
        <Banner>Banner>

        
        <div class="course">
            <el-row>
                <el-col :span="6" v-for="(o, index) in 8" :key="o">
                    <el-card :body-style="{ padding: '0px' }" class="course_card">
                        <img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g0zd133mj20l20a875i.jpg" class="image">
                        <div style="padding: 14px;">
                            <span>推荐的课程span>
                            <div class="bottom clearfix">
                                <time class="time">价格:100元time>
                                <el-button type="text" class="button">查看详情el-button>
                            div>
                        div>
                    el-card>
                el-col>
            el-row>
        div>
        <img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g112oiclj224l0u0jxl.jpg" alt="" height="500px"
             width="100%">

        <Footer>Footer>
    div>
template>

<script>
    import Footer from "@/components/Footer";
    import Header from "@/components/Header";
    import Banner from "@/components/Banner";

    export default {
        name: 'HomeView',
        data() {
            return {}
        },
        components: {
            Footer,
            Header,
            Banner
        }
    }
script>

<style scoped>
    .time {
        font-size: 13px;
        color: #999;
    }

    .bottom {
        margin-top: 13px;
        line-height: 12px;
    }

    .button {
        padding: 0;
        float: right;
    }

    .image {
        width: 100%;
        display: block;
    }

    .clearfix:before,
    .clearfix:after {
        display: table;
        content: "";
    }

    .clearfix:after {
        clear: both
    }

    .course {
        margin-left: 20px;
        margin-right: 20px;
    }

    .course_card {
        margin: 50px;
    }
style>

Banner.vue

<template>
    <div class="banner">
        <el-carousel :interval="5000" arrow="always" height="400px">
            <el-carousel-item v-for="item in 4" :key="item">
                <img src="../assets/img/banner1.png" alt="">
            el-carousel-item>
        el-carousel>
    div>
template>

<script>
    export default {
        name: "Banner"
    }
script>

<style scoped>


    el-carousel-item {
        height: 400px;
        min-width: 1200px;
    }

    .el-carousel__item img {
        height: 400px;
        margin-left: calc(50% - 1920px / 2);
    }
style>

Header.vue

<template>
    <div class="header">
        <div class="slogan">
            <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活p>
        div>
        <div class="nav">
            <ul class="left-part">
                <li class="logo">
                    <router-link to="/">
                        <img src="../assets/img/head-logo.svg" alt="">
                    router-link>
                li>
                <li class="ele">
                    <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课span>
                li>
                <li class="ele">
                    <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课span>
                li>
                <li class="ele">
                    <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课span>
                li>
            ul>

            <div class="right-part">
                <div>
                    <span>登录span>
                    <span class="line">|span>
                    <span>注册span>
                div>
            div>
        div>
    div>

template>

<script>

    export default {
        name: "Header",
        data() {
            return {
                url_path: sessionStorage.url_path || '/',
            }
        },
        methods: {
            goPage(url_path) {
                // 已经是当前路由就没有必要重新跳转
                if (this.url_path !== url_path) {
                    this.$router.push(url_path);
                }
                sessionStorage.url_path = url_path;
            },
        },
        created() {
            sessionStorage.url_path = this.$route.path;
            this.url_path = this.$route.path;
        }
    }
script>

<style scoped>
    .header {
        background-color: white;
        box-shadow: 0 0 5px 0 #aaa;
    }

    .header:after {
        content: "";
        display: block;
        clear: both;
    }

    .slogan {
        background-color: #eee;
        height: 40px;
    }

    .slogan p {
        width: 1200px;
        margin: 0 auto;
        color: #aaa;
        font-size: 13px;
        line-height: 40px;
    }

    .nav {
        background-color: white;
        user-select: none;
        width: 1200px;
        margin: 0 auto;

    }

    .nav ul {
        padding: 15px 0;
        float: left;
    }

    .nav ul:after {
        clear: both;
        content: '';
        display: block;
    }

    .nav ul li {
        float: left;
    }

    .logo {
        margin-right: 20px;
    }

    .ele {
        margin: 0 20px;
    }

    .ele span {
        display: block;
        font: 15px/36px '微软雅黑';
        border-bottom: 2px solid transparent;
        cursor: pointer;
    }

    .ele span:hover {
        border-bottom-color: orange;
    }

    .ele span.active {
        color: orange;
        border-bottom-color: orange;
    }

    .right-part {
        float: right;
    }

    .right-part .line {
        margin: 0 10px;
    }

    .right-part span {
        line-height: 68px;
        cursor: pointer;
    }
style>

Footer.vue

<template>
    <div class="footer">
        <ul>
            <li>关于我们li>
            <li>联系我们li>
            <li>商务合作li>
            <li>帮助中心li>
            <li>意见反馈li>
            <li>新手指南li>
        ul>
        <p>Copyright ? luffycity.com版权所有 | 京ICP备17072161号-1p>
    div>
template>

<script>
    export default {
        name: "Footer"
    }
script>

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

    .footer ul {
        margin: 0 auto 16px;
        padding-top: 38px;
        width: 810px;
    }

    .footer ul li {
        float: left;
        width: 112px;
        margin: 0 10px;
        text-align: center;
        font-size: 14px;
    }

    .footer ul::after {
        content: "";
        display: block;
        clear: both;
    }

    .footer p {
        text-align: center;
        font-size: 12px;
    }
style>

后台主页轮播图接口

基表设计

# utils/model.py/BaseModel
from django.db import models
# 5个公共字段
class BaseModel(models.Model):
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_time = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
    is_delete = models.BooleanField(default=False, verbose_name='是否删除')
    is_show = models.BooleanField(default=True, verbose_name='是否上架')
    orders = models.IntegerField(verbose_name='优先级')
    class Meta:
        abstract = True  # 表示它是虚拟的,不在数据库中生成表,它只用来做继承

Banner表

from django.db import models

# Create your models here.
# 轮播图接口---》轮播图表
from utils.model import BaseModel
class Banner(BaseModel):
    # 顺序,插入时间, 是否显示,是否删除。。。----》后期写课程的表也会用到这些字段--->仿AbstractUser,写一个基表,以后继承这个表
    # 继承过来,只需要写自有字段即可:title,image,info,link
    title = models.CharField(max_length=16, unique=True, verbose_name='名称')
    image = models.ImageField(upload_to='banner', verbose_name='图片')
    # 写接口---》app---》前端配合一个接口---》实现打开app,就有广告图片---》点击广告图片调整到app内部或者使用浏览器打开
    # 一打开app,先打开的页面是什么,写app的人写的---》整一张大图充满全屏即可--》配合一个接口,返回一张大图
    # app打开广告接口---》{code:100,msg:成功,img:{img:127.0.0.1/img/1.png,link:'www.baidu.com',type:2}}
    link = models.CharField(max_length=64, verbose_name='跳转链接') # 在前端点击图片,会跳转到某个地址
    info = models.TextField(verbose_name='详情')  # 也可以用详情表,宽高出处
    class Meta:
        db_table = 'luffy_banner'
        verbose_name_plural = '轮播图表'

    def __str__(self):
        return self.title

迁移数据库,创建超级用户

# python manage.py makemigrations  ---》如果没有变化,是app没注册
# python manage.py migrate
# python manage.py createsuperuser  --->创建个用户

引入simpleui

# 下载
pip install django-simpleui
# 注册app
INSTALLED_APPS = [
      'simpleui',
      ...
  ]
# 在admin中写
from django.contrib import admin
from .models import Banner

@admin.register(Banner)
class BannerAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'link','is_show', 'is_delete')

    # 增加自定义按钮
    actions = ['make_copy']
    def make_copy(self, request, queryset):
        # 选中一些数据,点击 【自定义按钮】  触发方法执行,传入你选中 queryset
        # 保存,删除
        print(queryset)
    make_copy.short_description = '自定义按钮'

home路由

from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import BannerView

router = SimpleRouter()
router.register('banner', BannerView, 'banner')
urlpatterns = [
    path('', include(router.urls)),

]

总路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/home/', include('home.urls')), # http://127.0.0.1:8000/api/v1/home/banner/
]

视图类

from .models import Banner
from .serializer import BannerSerializer
from utils.response import APIResponse
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
class BannerView(GenericViewSet,ListModelMixin):
    # 获取所有接口-list,自动生成路由
    queryset = Banner.objects.filter(is_delete=False,is_show=True).order_by('orders')
    serializer_class =BannerSerializer

    def list(self, request, *args, **kwargs): # 重写list
        res=super().list(request, *args, **kwargs)
        return APIResponse(result=res.data)

序列化类

from rest_framework import serializers
from .models import Banner

class BannerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Banner
        fields = ['title', 'image', 'link', 'orders']

跨域问题解决

# 现在写好了后端接口,前端加载数据---》加载不过来,报错,--》报跨域的错误

#  同源策略 ---》浏览器的规定
    -请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同,否则,加载回来的数据就会禁止
  -前端:http://127.0.0.1:8080
  -后端:http://127.0.0.1:8000
  -这俩属于不同源,协议,地址一样,但是端口不一样,所以请求成功,但是到了浏览器被禁止掉了,因为浏览器的同源策略
     -前后端分离,就会遇到这个问题,解决这个问题
  

# jsonp:出现了跨域问题---》有的东西不出跨域问题---》img,script,link--》回调
# https://www.zhihu.com/question/19966531


# 通过CORS(跨域资源共享)
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能

实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信
----只需要在响应头中指定,允许跨域即可----

# cors有两类请求
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
# 只要同时满足以下两大条件,就属于简单请求,否则就是非简单请求
1-请求方法是以下三种方法之一:
HEAD
GET
POST
2-HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

问:post,josn格式是什么请求? 非简单


# 简单请求和非简单请求的区别
简单请求:一次请求,直接发真正的请求,如果允许,数据拿回来,如果不允许,浏览器拦截
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。非简单请求发两次,第一次是OPTIONS请求,如果允许跨域,再发真正的请求


# 解决跨域-->分成简单和非简单请求处理
    -简单请求再响应头中加入:"Access-Control-Allow-Origin":"*"
  -非简单,咱们要加判断,如果是OPTIONS请求,在响应头中加入允许

# 自行解决跨域---》django中写个中间件,处理跨域--->配置到配置文件中
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
    def process_response(self,request,response):
        if request.method=="OPTIONS":
            #可以加*
            response["Access-Control-Allow-Headers"]="Content-Type"
        response["Access-Control-Allow-Origin"] = "*"
        return response
      
      
 # 经常遇到的东西,一定会有第三方解决方案---》我们使用第三方解决
    -第一步:下载:pip install django-cors-headers
    -第二步:app中注册
    INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
  )
  -第三步:中间件注册
    MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
  ]
  -第四步:配置文件配置

# 允许简单请求,所有地址 相当于CORS_ORIGIN_ALLOW_ALL="*"
CORS_ALLOW_ALL_ORIGINS = True
# 运行的请求
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'POST',
'PUT',
)


# 允许的请求头
CORS_ALLOW_HEADERS = (
'accept-encoding',
'authorization', # jwt
'content-type', # json
'origin',
'user-agent',
'Pragma',
)



前端后互通

Banner.vue





后端自定义配置

# 在setting文件夹下新建 user_settings.py
# 用户自己的配置,单独放到另一个py文件中
BANNER_COUNT=3


# 在dev.py中导入
# 导入用户自定义的配置
from .user_settings import *

相关