luffy轮播图+登录

发布于:2022-11-10 ⋅ 阅读:(443) ⋅ 点赞:(0)

后台主页模块接口

首页轮播图接口

一张表写一个app, 创建一个app,写轮播图

基表

from django.db import models

# Create your models here.
# 轮播图表
# class Banner(models.Model):
# 将其只作为基表使用
class BaseModel(models.Model):

    # 是否删除,展示,创建时间
    create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
    update_time = models.DateTimeField(auto_now=True,verbose_name='最后更新时间')
    is_delete = models.BooleanField(default=False,verbose_name='是否删除')
    is_display = models.BooleanField(default=True,verbose_name='是否上架展示')
    privilege = models.IntegerField(verbose_name='优先级')

    class Meta:
        # 如果表迁移,这个表就会生成, 为了不让表生成苦于加这句话
        abstract = True  # 虚拟表,只用来做继承,不在数据库生成表

但是上述字段,在别的表中可能也会用到, 于是我们将它抽出来,成为一个基表, 后续有需要使用这些字段的表直接继承它就可以了, 减少代码的编写。 将其放在utils/models.py中【utils文件夹内存放公共的数据和资源】

轮播图表

from utils.models import BaseModel
from django.db import models


# 轮播图表
class Banner(BaseModel):
    # 图片地址,名字,图片名字,link地址【前端点击,会跳到图片】

    title = models.CharField(max_length=32,unique=True,verbose_name='名字')
    image = models.ImageField(upload_to='banner',verbose_name='图片')
    link = models.CharField(max_length=64,verbose_name='跳转链接')  # course
    desc = models.TextField(verbose_name='详情')  # 也可以用详情表

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

    def __str__(self):
        return self.title


执行迁移命令

轮播图接口

路由分发

 urls.py  总路由


from django.contrib import admin
from django.urls import path,include
from home import views
from django.views.static import serve
from django.conf import settings
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('test/', views.TestView.as_view()),

    # 路由分发
    path('api/v1/home/',include('home.urls')),
    # 开启media访问
    path('media/<path:path>',serve,kwargs={'document_root':settings.MEDIA_ROOT}),
]

home/urls.py app下的路由


from home import views


from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('banner',views.BannerView,'banner')

urlpatterns = [

]

urlpatterns+=router.urls

views.py

from django.shortcuts import render

# Create your views here.
from .models import Banner
from .serializer import BannerSerializer

# 自动生成路由
from rest_framework.viewsets import GenericViewSet

# 获取所有的
from rest_framework.mixins import ListModelMixin

class BannerView(GenericViewSet,ListModelMixin):
    queryset = Banner.objects.all().filter(is_delete=False,is_display=True).order_by('privilege')
    serializer_class = BannerSerializer

 serializer.py


from rest_framework import serializers
from .models import Banner


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

测试访问一下

重写list方法,获取所有。 返回统一的格式。

  utils/views.py 封装一下获取所有数据方法,方便后续,少写代码。

from rest_framework.mixins import ListModelMixin
from utils.response import APIResponse

class CommonListModelMixin(ListModelMixin):
    def list(self, request, *args, **kwargs):
        res = super().list(request,*args,**kwargs)
        return APIResponse(result=res.data)

home/view.py

from django.shortcuts import render

# Create your views here.
from .models import Banner
from .serializer import BannerSerializer

# 自动生成路由
from rest_framework.viewsets import GenericViewSet

# 获取所有的
from utils.view import CommonListModelMixin

class BannerView(GenericViewSet,CommonListModelMixin):
    queryset = Banner.objects.all().filter(is_delete=False,is_display=True).order_by('privilege')
    serializer_class = BannerSerializer

再次访问就可以看到已经统一了数据返回格式

接下来去后台填充数据

先做汉化处理

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

创建超级用户  [密码不展示】

python manage.py createsuperuser

admin里注册


from .models import Banner

admin.site.register(Banner)

后台管理采用simpleui

下载安装

app中注册

INSTALLED_APPS = [
    'simpleui',]

添加数据

 后端完成后我们来接通前端

 settings.js    以后访问的路径都是api/v1/...

export default {
    BASE_URL:'http://127.0.0.1:8000/api/v1/'
}

HomeVue.vue

export default {
  name: 'HomeView',
  data(){
    return {}

  },
  created() {   
 // 联通前后端, 注意斜杠得添加, 前端不会追加斜杠
    this.$axios.get(this.$settings.BASE_URL+'/home/banner/').then(res=>{
      console.log(res)

    })
  }

}

然后我们发现前后端交互的时候出现了跨域问题

 

具体成因及解决方案参考此篇博文 

django中的跨域问题以及解决策略_Yietong309的博客-CSDN博客

前端首页

HomeView.vue 页面组件
Top.vue   头部组件
Banner.vue   轮播图组件
Bottom.vue   尾部组件

前端切图

我们需要写头部top,轮播图banner和尾部bottom组件

组件写进componetnts里

Top.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: "Top",
  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>

Banner.vue

<template>
  <div class="banner">
    <el-carousel :interval="5000" arrow="always" height="400px">
      <el-carousel-item v-for="item in bannerList" :key="item.title">
        <div v-if="item.image.indexOf('http')==-1">
          <router-link :to="item.link"><img :src="item.image" alt=""></router-link>
        </div>
        <div v-else>
          <a :href="item.link"><img :src="item.image" alt=""></a>
        </div>

      </el-carousel-item>
    </el-carousel>

  </div>

</template>

<script>
export default {
  name: "Banner",
  data() {
    return {
      bannerList: []
    }
  },
  created() {
    this.$axios.get(this.$settings.BASE_URL + 'home/banner/').then(res => {
      this.bannerList = res.data.result

    })
  }
}
</script>

<style scoped>
.el-carousel__item {
  height: 400px;
  min-width: 1200px;
}

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

.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;
}
</style>

Bottom.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号-1</p>
  </div>
</template>

<script>
export default {
  name: "Bottom"
}
</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>

HomeVue.vue

<template>
  <div class="home">
    <Header></Header>
    <Banner></Banner>
    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
    <Footer></Footer>
  </div>
</template>

<script>
import Top from "@/components/Top";
import Banner from "@/components/Banner";
import Bottom from "@/components/Bottom";

export default {
  name: 'HomeView',
  data() {
    return {}
  },
  components: {
    Top, Banner, Bottom
  }

}
</script>

 首页中间部分样式

<div class="course">
      <el-row>
        <el-col :span="6" v-for="(o, index) in 8" :key="o" class="course_detail">
          <el-card :body-style="{ padding: '0px' }">
            <img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g0zd133mj20l20a875i.jpg"
                 class="image">
            <div style="padding: 14px;">
              <span>推荐课程</span>
              <div class="bottom clearfix">
                <time class="time">价格:999</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="" width="100%" height="500px">
    
    
    
    
<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_detail {
  padding: 50px;
}
</style>
    
    

首页效果图 

登录注册功能设计

后端接口


  1 账号/手机号/邮箱+密码登录接口
    2 手机号+验证码登录接口
    3 发送手机验证码接口  (第三方发送短信)
    4 注册接口--》手机号,验证码,密码
    5 判断手机号是否存在接口


网站公告

今日签到

点亮在社区的每一天
去签到