Python项目45-前后端分离Home主页及后台(开撸)

2022-09-26 14:03:02 浏览数 (1)

  • 前端页面
    • 主页
  • 后台home设计
    • 表设计
  • 前后台跨域交互

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


前端页面

主页

我们把主页分成三部分: 1.导航栏 2.轮播图 3.页脚


图片

先把图片放入img目录中


全局做一个CSS reset

assets/css/global.css

代码语言:javascript复制
/* 声明全局样式和项目的初始化样式 */
body, h1, h2, h3, h4, 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; /* 合并边框 */
}

导航栏

创建Header组件

Header也就是我们的导航栏

componets/Header.vue

代码语言:javascript复制
<template>
    <div class="header-box">
        <div class="header">
            <div class="content">
                <div class="logo full-left">
                    <router-link to="/"><img @click="jump('/')" src="@/assets/img/logo.svg" alt=""></router-link>
                </div>
                <ul class="nav full-left">
                    <li><span @click="jump('/course')" :class="this_nav=='/course'?'this':''">免费课</span></li>
                    <li><span @click="jump('/light-course')" :class="this_nav=='/light-course'?'this':''">轻课</span></li>
                    <li><span>学位课</span></li>
                    <li><span>题库</span></li>
                    <li><span>老男孩教育</span></li>
                </ul>
                <div class="login-bar full-right">
                    <div class="shop-cart full-left">
                        <img src="@/assets/img/cart.svg" alt="">
                        <span><router-link to="/cart">购物车</router-link></span>
                    </div>
                    <div class="login-box full-left">
                        <span>登录</span>
                        &nbsp;|&nbsp;
                        <span>注册</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: "Header",
        data() {
            return {
                this_nav: "",
            }
        },
        created() {
            this.this_nav = localStorage.this_nav;
        },
        methods: {
            jump(location) {
                localStorage.this_nav = location;
                // vue-router除了提供router-link标签跳转页面以外,还提供了js跳转的方式
                this.$router.push(location);
            }
        }
    }
</script>

<style scoped>
    .header-box {
        height: 80px;
    }

    .header {
        width: 100%;
        height: 80px;
        box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        margin: auto;
        z-index: 99;
        background: #fff;
    }

    .header .content {
        max-width: 1200px;
        width: 100%;
        margin: 0 auto;
    }

    .header .content .logo {
        height: 80px;
        line-height: 80px;
        margin-right: 50px;
        cursor: pointer;
    }

    .header .content .logo img {
        vertical-align: middle;
    }

    .header .nav li {
        float: left;
        height: 80px;
        line-height: 80px;
        margin-right: 30px;
        font-size: 16px;
        color: #4a4a4a;
        cursor: pointer;
    }

    .header .nav li span {
        padding-bottom: 16px;
        padding-left: 5px;
        padding-right: 5px;
    }

    .header .nav li span a {
        display: inline-block;
    }

    .header .nav li .this {
        color: #4a4a4a;
        border-bottom: 4px solid #ffc210;
    }

    .header .nav li:hover span {
        color: #000;
    }

    .header .login-bar {
        height: 80px;
    }

    .header .login-bar .shop-cart {
        margin-right: 20px;
        border-radius: 17px;
        background: #f7f7f7;
        cursor: pointer;
        font-size: 14px;
        height: 28px;
        width: 88px;
        margin-top: 30px;
        line-height: 32px;
        text-align: center;
    }

    .header .login-bar .shop-cart:hover {
        background: #f0f0f0;
    }

    .header .login-bar .shop-cart img {
        width: 15px;
        margin-right: 4px;
        margin-left: 6px;
    }

    .header .login-bar .shop-cart span {
        margin-right: 6px;
    }

    .header .login-bar .login-box {
        margin-top: 33px;
    }

    .header .login-bar .login-box span {
        color: #4a4a4a;
        cursor: pointer;
    }

    .header .login-bar .login-box span:hover {
        color: #000000;
    }

    .full-left {
        float: left !important;
    }

    .full-right {
        float: right !important;
    }

    .el-carousel__arrow {
        width: 120px;
        height: 120px;
    }

    .el-checkbox__input.is-checked .el-checkbox__inner,
    .el-checkbox__input.is-indeterminate .el-checkbox__inner {
        background: #ffc210;
        border-color: #ffc210;
        border: none;
    }

    .el-checkbox__inner:hover {
        border-color: #9b9b9b;
    }

    .el-checkbox__inner {
        width: 16px;
        height: 16px;
        border: 1px solid #9b9b9b;
        border-radius: 0;
    }

    .el-checkbox__inner::after {
        height: 9px;
        width: 5px;
    }
</style>

导入到主页中

首先注册导航栏,然后将导航栏添加到我们的主页中

代码语言:javascript复制
<template>
    <div class="home">
        <Header/>
    </div>
</template>
<script>
    import Header from "@/components/Header";
    export default {
        name: 'home',
        components: {Header},
        Header,
    }
</script>


轮播图

创建轮播图组件Banner

components/Banner.vue

代码语言:javascript复制
<template>
    <el-carousel height="520px" :interval="3000" arrow="always">
        <!--<el-carousel-item>-->
        <!--    <img src="@/assets/img/banner1.png" alt="">-->
        <!--</el-carousel-item>-->
        <!--<el-carousel-item>-->
        <!--    <img src="@/assets/img/banner2.png" alt="">-->
        <!--</el-carousel-item>-->
        <!--<el-carousel-item>-->
        <!--    <img src="@/assets/img/banner3.png" alt="">-->
        <!--</el-carousel-item>-->

        <el-carousel-item v-for="banner in banner_list" :key="banner.name">
            <a :href="banner.link">
                <img :src="banner.image" alt="" :title="banner.note">
            </a>
        </el-carousel-item>

    </el-carousel>
</template>
<script>
    export default {
        name: "Banner",
        data() {
            return {
                banner_list: []
            }
        },
        created() {
            this.$axios({
                url: this.$settings.base_url   '/home/banners/',
                method: 'get',
            }).then(response => {
                // window.console.log(response.data);
                this.banner_list = response.data;
            }).catch(errors => {
                window.console.log(errors)
            })
        }
    }
</script>

<style scoped>
    .el-carousel__item h3 {
        color: #475669;
        font-size: 18px;
        opacity: 0.75;
        line-height: 300px;
        margin: 0;
    }

    .el-carousel__item:nth-child(2n) {
        background-color: #99a9bf;
    }

    .el-carousel__item:nth-child(2n 1) {
        background-color: #d3dce6;
    }

    .el-carousel__item img {
        text-align: center;
        height: 520px;
        margin: 0 auto;
        display: block;
    }
</style>

注册Banner并且使用Banner

代码语言:javascript复制
<template>
    <div class="home">
        <Header/>
        <Banner/>
    </div>
</template>

<script>
    import Header from '@/components/Header'
    import Banner from '@/components/Banner'

    export default {
        name: 'home',
        components: {
            Header,
            Banner,
        },
    }
</script>


页脚

在components目录下创建有个Footer组件

components/Footer.vue

代码语言:javascript复制
<template>
    <div class="footer">
        <ul>
            <li>关于我们</li>
            <li>联系我们</li>
            <li>商务合作</li>
            <li>帮助中心</li>
            <li>意见反馈</li>
            <li>新手指南</li>
        </ul>
        <p>Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p>
    </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>

Home.vue中注册页脚组件,并使用

代码语言:javascript复制
<template>
    <div class="home">
        <Header/>
        <Banner/>
        <Footer/>
    </div>
</template>

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

    export default {
        name: 'home',
        components: {
            Header,
            Banner,
            Footer,
        },
    }
</script>

后台home设计


创建home模块

代码语言:javascript复制
## 在apps目录下
(luffy) bash-3.2$ pwd
/Users/driverzeng/Desktop/luffy/luffyapi/luffyapi/apps

## 创建home
(luffy) bash-3.2$ python ../../manage.py startapp home

settings配置

注册drf组件和home组件

settings/dev.py

代码语言:javascript复制
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'user',
    'home',
]

总路由做路由分发

luffyapi/urls.py

代码语言:javascript复制
from django.contrib import admin
from django.urls import path, re_path, include
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    ## 路由分发user模块
    path('user/', include('user.urls')),
    ## 路由分发home模块
    path('home/', include('home.urls')),
    ## 图片上传路径,必须是正则路由
    re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
]

表设计


基础表设计设计BaseModel

utils/models.py

代码语言:javascript复制
from django.db import models

class BaseModel(models.Model):
    orders = models.IntegerField(verbose_name='显示顺序')
    is_show = models.BooleanField(verbose_name="是否上架", default=False)
    is_delete = models.BooleanField(verbose_name="逻辑删除", default=False)

    class Meta:
        abstract = True

轮播图,表设计Banner

apps/home/models.py

代码语言:javascript复制
from django.db import models
from utils.models import BaseModel


class Banner(BaseModel):
    image = models.ImageField(upload_to='banner', verbose_name='轮播图', null=True, blank=True)
    name = models.CharField(max_length=150, verbose_name='轮播图名称')
    note = models.CharField(max_length=150, verbose_name='备注信息')
    link = models.CharField(max_length=150, verbose_name='轮播图广告地址')

    class Meta:
        db_table = 'luffy_banner'
        verbose_name = '轮播图'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

数据库迁移

代码语言:javascript复制
(luffy) bash-3.2$ python manage.py makemigrations
(luffy) bash-3.2$ python manage.py migrate

子路由

apps/home/urls.py

代码语言:javascript复制
from django.urls import path, re_path
from . import views

urlpatterns = [
    path('banners/', views.BannerListAPIView.as_view())
]

home序列化

apps/home/serializers.py

代码语言:javascript复制
from rest_framework.serializers import ModelSerializer
from . import models


class BannerModelSerializer(ModelSerializer):
    class Meta:
        model = models.Banner
        fields = ['name', 'note', 'image', 'link']

视图层

代码语言:javascript复制
from rest_framework.generics import ListAPIView
from utils.repsonse import APIResponse
from . import models, serializers


class BannerListAPIView(ListAPIView):
    queryset = models.Banner.objects.filter(is_delete=False, is_show=True).order_by('-orders')
    serializer_class = serializers.BannerModelSerializer

前后台跨域交互


解决后台跨域问题

安装django-cors-headers

代码语言:javascript复制
(luffy) bash-3.2$ pip install django-cors-headers

配置允许跨域

settings/dev.py

代码语言:javascript复制
### 注册跨域app
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    ## 注册cors,解决跨域问题
    'corsheaders',
    'user',
    'home',
]

### 添加跨域中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ## 添加跨域中间件
    'corsheaders.middleware.CorsMiddleware',
]

### 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True

配置Banner组件ajax与后台交互

components/Banner.vue

代码语言:javascript复制
<script>
    export default {
        name: "Banner",
        // 添加钩子,渲染页面的时候,axios与后台交互
        created() {
            this.$axios({
                url: this.$settings.base_url   '/home/banners/',
                method: 'get',
            }).then(response => {
                console.log(response.data)
            }).catch((errors) => {
                console.log(errors)
            })
        }
    }
</script>

因为数据库没有数据,但是我们交互成功了。

0 人点赞