Python輪播圖與導航欄功能的實現(xiàn)流程全講解
輪播圖功能
安裝依賴模塊
圖片處理模塊
pip install pillow
上傳文件相關(guān)配置
由于我們需要在后臺上傳我們的輪播圖圖片,所以我們需要在django中配置一下上傳文件的相關(guān)配置,有了它之后,就不需要我們自己寫上傳文件,保存文件的操作了,看配置
dev.py
STATIC_URL = '/static/' # 設置django的靜態(tài)文件目錄 # STATICFILES_DIRS = [ # os.path.join(BASE_DIR,"static") # ] # 項目中存儲上傳文件的根目錄[暫時配置],注意,uploads目錄需要手動創(chuàng)建否則上傳文件時報錯 MEDIA_ROOT = os.path.join(BASE_DIR, "uploads") # 訪問上傳文件的url地址前綴 MEDIA_URL = "/media/"
總路由urls.py
在django項目中轉(zhuǎn)換上傳文件的Url地址,總路由urls.py新增代碼:
from django.contrib import admin from django.urls import path, re_path, include from django.views.static import serve from django.conf import settings import xadmin xadmin.autodiscover() # version模塊自動注冊需要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() urlpatterns = [ # path('admin/', admin.site.urls), path(r'xadmin/', xadmin.site.urls), re_path(r'media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}), ]
注冊home子應用
因為當前功能是drf的第一個功能,所以我們先創(chuàng)建一個子應用home,創(chuàng)建在lyapi/apps目錄下
cd lyapi/apps/
python manage.py startapp home
注冊home子應用,因為子應用的位置發(fā)生了改變,所以為了原來子應用的注冊寫法,所以新增一個導包路徑:
dev.py
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 新增一個系統(tǒng)導包路徑 import sys #sys.path使我們可以直接import導入時使用到的路徑,所以我們直接將我們的apps路徑加到默認搜索路徑里面去,那么django就能直接找到apps下面的應用了 sys.path.insert(0,os.path.join(BASE_DIR,"apps")) ... INSTALLED_APPS = [ # 注意,加上drf框架的注冊 ... 'rest_framework', ... # 子應用 'home', ]
創(chuàng)建輪播圖的model模型
apps/home/models.py
from django.db import models # Create your models here. class Banner(models.Model): """輪播廣告圖模型""" # 模型字段 title = models.CharField(max_length=500, verbose_name="廣告標題") link = models.CharField(max_length=500, verbose_name="廣告鏈接") # upload_to 設置上傳文件的保存子目錄,將來上傳來的文件會存到我們的media下面的banner文件夾下,這里存的是圖片地址。 image_url = models.ImageField(upload_to="banner", null=True, blank=True, max_length=255, verbose_name="廣告圖片") remark = models.TextField(verbose_name="備注信息") is_show = models.BooleanField(default=False, verbose_name="是否顯示") # 將來輪播圖肯定會更新,到底顯示哪些 orders = models.IntegerField(default=1, verbose_name="排序") # 輪播圖優(yōu)先顯示,default數(shù)字越大越優(yōu)先顯示 is_deleted = models.BooleanField(default=False, verbose_name="是否刪除") # 表信息聲明 class Meta: db_table = "ly_banner" verbose_name = "輪播廣告" verbose_name_plural = verbose_name # 自定義方法[自定義字段或者自定義工具方法] def __str__(self): return self.title
執(zhí)行數(shù)據(jù)庫遷移指令
python manage.py makemigrations
python manage.py migrate
創(chuàng)建Banner的序列化器
apps/home/serializers.py
from rest_framework import serializers from . import models class BannerModelSeiralizer(serializers.ModelSerializer): class Meta: model = models.Banner fields = ['id', 'title', 'link', 'image_url']
創(chuàng)建Banner的視圖類
apps/home/views.py
from rest_framework.generics import ListAPIView from . import models from .serializer import BannerModelSeiralizer # 這個是把所有的常量參數(shù)放在一個文件內(nèi),誰用誰拿 from lyapi.settings import contains # Create your views here. class BannerView(ListAPIView): queryset = models.Banner.objects.filter(is_show=True, is_deleted=False).order_by('orders')[0:contains.BANNER_LENGTH] serializer_class = BannerModelSeiralizer
在settings配置文件夾中創(chuàng)建一個constants.py配置文件,將來里面存放我們所有的一些常量信息配置,比如上面的輪播圖數(shù)據(jù)切片長度
settings/constant.py
# 輪播圖顯示條數(shù)
BANNER_LENGTH = 3
配置Banner的路由
總路由utils/urls.py
from django.urls import path, re_path, include from django.views.static import serve from django.conf import settings import xadmin xadmin.autodiscover() # version模塊自動注冊需要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() urlpatterns = [ path('admin/', admin.site.urls), re_path(r'media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}), path(r'home/', include('home.urls')), ]
應用中的路由apps/home/urls.py
from django.urls import path, re_path from django.conf import settings from . import views urlpatterns = [ path(r'banner/', views.BannerView.as_view()), ]
配置Xadmin
配置文件注冊Xadmin應用
settings/dev.py
INSTALLED_APPS = [ ... 'home', 'users', 'xadmin', 'crispy_forms', 'reversion', ] # LANGUAGE_CODE = 'en-us' # 原來配置文件中的兩個原配置注掉,用我們的 # TIME_ZONE = 'UTC' # 修改使用中文界面 LANGUAGE_CODE = 'zh-Hans' # 修改時區(qū) TIME_ZONE = 'Asia/Shanghai'
xadmin有建立自己的數(shù)據(jù)庫模型類,需要進行數(shù)據(jù)庫遷移
python manage.py makemigrations
python manage.py migrate
在總路由中添加xadmin的路由信息
from django.urls import path, re_path, include from django.views.static import serve from django.conf import settings import xadmin xadmin.autodiscover() # version模塊自動注冊需要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() urlpatterns = [ # path('admin/', admin.site.urls), path(r'xadmin/', xadmin.site.urls), ]
給Xadmin配置基本的站點信息
home/adminx.py
import xadmin from xadmin import views class BaseSetting(object): """xadmin的基本配置""" enable_themes = True # 開啟主題切換功能 use_bootswatch = True xadmin.site.register(views.BaseAdminView, BaseSetting) class GlobalSettings(object): """xadmin的全局配置""" site_title = "莽夫?qū)W城" # 設置站點標題 site_footer = "莽夫?qū)W城有限公司" # 設置站點的頁腳 menu_style = "accordion" # 設置菜單折疊 xadmin.site.register(views.CommAdminView, GlobalSettings)
創(chuàng)建超級管理員
python manage.py createsuperuser
注冊輪播圖模型到xadmin中
apps/home/adminx.py
在當前子應用中創(chuàng)建adminx.py,添加如下代碼
class BannerXadmin(object): # 需要展示的字段用中文顯示 list_display = ['id', 'title', 'link', 'image_url', 'is_show'] # 注冊Xadmin xadmin.site.register(models.Banner, BannerXadmin)
修改后端Xadmin中子應用名稱
apps/home/apps.py
from django.apps import AppConfig class HomeConfig(AppConfig): name = 'home' verbose_name = '我的首頁'
apps/home/__ init__.py
default_app_config = "home.apps.HomeConfig"
給輪播圖添加測試數(shù)據(jù)
經(jīng)過上面的操作,我們就完成了輪播圖的API接口,接下來,可以考慮提交一個代碼版本.
git add .
git commit -m "服務端實現(xiàn)輪播圖的API接口"
git push origin master
web端代碼獲取數(shù)據(jù)
src/components/Home.vue
<template> <div class="home"> <Header></Header> <Banner></Banner> <Footer></Footer> </div> </template> <script> import Header from '@/components/common/Header' import Banner from '@/components/common/Banner' import Footer from '@/components/common/Footer' export default { name: "Home", components: { Header, Banner, Footer, } } </script> <style scoped> </style>
src/components/common/Banner.vue
<template> <!-- <h1>輪播圖組件</h1>--> <el-carousel indicator-position="outside" height="400px"> <el-carousel-item v-for="(value,index) in banner_list" :key="index"> <a :href="value.link" rel="external nofollow" target="_blank"> <img :src="value.image_url" alt="" style="width: 100%;height: 400px"> </a> </el-carousel-item> </el-carousel> </template> <script> //router-link主要用于站內(nèi)頁面跳轉(zhuǎn),使用的是相對路徑 //a標簽用于外部鏈接頁面跳轉(zhuǎn) export default { name: "Banner", data() { return { banner_list: [], } }, created() { this.$axios.get(`${this.$settings.host}/home/banner/`) .then((res) => { this.banner_list = res.data; }) .catch((error) => { }) }, } </script> <style scoped> </style>
導航欄的實現(xiàn)
前端導航欄子組件Header的代碼
lyweb/src/components/common/Header.vue
<template> <div class="total-header"> <div class="header"> <el-container> <el-header height="80px" class="header-cont"> <el-row> <el-col class="logo" :span="3"> <a href="/" rel="external nofollow" > <img src="@/assets/head-logo.svg" alt=""> </a> </el-col> <el-col class="nav" :span="10"> <el-row> <el-col :span="4" v-for="(top_nav, index) in nav_top_list" :key="top_nav.id"> <router-link :to="top_nav.link" v-if="!top_nav.is_site">{{ top_nav.title }}</router-link> <a :href="top_nav.link" rel="external nofollow" target="_blank" v-else>{{ top_nav.title }}</a> </el-col> </el-row> </el-col> <el-col :span="11" class="header-right-box"> <div class="search"> <input type="text" id="Input" placeholder="請輸入想搜索的課程" style="" @blur="inputShowHandler" ref="Input" v-show="!s_status"> <ul @click="ulShowHandler" v-show="s_status" class="search-ul"> <span>Python</span> <span>Linux</span> </ul> <p> <img class="icon" src="@/assets/sousuo1.png" alt="" v-show="s_status"> <img class="icon" src="@/assets/sousuo2.png" alt="" v-show="!s_status"> <img class="new" src="@/assets/new.png" alt=""> </p> </div> <div class="register" v-show="!token"> <router-link to="/login"> <button class="signin">登錄</button> </router-link> | <a target="_blank" rel="external nofollow" > <router-link to="/register"> <button class="signup">注冊</button> </router-link> </a> </div> <div class="shop-car" v-show="token"> <router-link to="/cart"> <b>6</b> <img src="@/assets/shopcart.png" alt=""> <span>購物車 </span> </router-link> </div> <div class="nav-right-box" v-show="token"> <div class="nav-right"> <router-link to="/myclass"> <div class="nav-study">我的教室</div> </router-link> <div class="nav-img" @mouseover="personInfoList" @mouseout="personInfoOut"> <img src="@/assets/touxiang.png" alt="" style="border: 1px solid rgb(243, 243, 243);"> <ul class="home-my-account" v-show="list_status" @mouseover="personInfoList"> <li> 我的賬戶 <img src="" alt="@/assets/back.svg"> </li> <li> 我的訂單 <img src="@/assets/back.svg" alt=""> </li> <li> 貝里小賣鋪 <img src="@/assets/back.svg" alt=""> </li> <li> 我的優(yōu)惠券 <img src="@/assets/back.svg" alt=""> </li> <li> <span> 我的消息 <b>(26)</b> </span> <img src="" alt=""> </li> <li> 退出 <img src="" alt=""> </li> </ul> </div> </div> </div> </el-col> </el-row> </el-header> </el-container> </div> </div> </template> <script> export default { name: "Header", data() { return { // 設置一個登錄狀態(tài)的標記,因為登錄注冊部分在登錄之后會發(fā)生變化 token: false, // false -- not login true -- login s_status: true, // 控制放大鏡顏色切換 list_status: false, // 控制個人中心下拉菜單是否顯示 nav_top_list: [], where: 0, // 記錄token的存放位置 } }, methods: { checklogin() { if (localStorage.token) { this.token = localStorage.token this.where = 1; } else if (sessionStorage.token) { this.token = sessionStorage.token this.where = 0; } else { return false; } // this.token = localStorage.token || sessionStorage.token; this.$axios.post(`${this.$settings.host}/users/verify_token/`, { token: this.token, }) .then((res) => { if (this.where === 0) { sessionStorage.token = res.data.token; } else { localStorage.token = res.data.token; } }) .catch((error) => { this.$confirm('請重新登錄', '提示', { confirmButtonText: '確定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$router.push('/login'); }).catch(() => { this.token = false; }) }) }, ulShowHandler() { this.s_status = false; // console.log(this.$refs.Input); // this.$refs.Input.focus(); this.$nextTick(() => { //延遲回調(diào)方法,Vue中DOM更新是異步的,也就是說讓Vue去顯示我們的input標簽的操作是異步的,如果我們直接執(zhí)行this.$refs.Input.focus();是不行的,因為異步的去顯示input標簽的操作可能還沒有完成,所有我們需要等它完成之后在進行DOM的操作,需要借助延遲回調(diào)對DOM進行操作,這是等這次操作對應的所有Vue中DOM的更新完成之后,在進行nextTick的操作。 this.$refs.Input.focus(); }) }, inputShowHandler() { // console.log('xxxxx') this.s_status = true; }, personInfoList() { this.list_status = true; }, personInfoOut() { this.list_status = false; }, get_nav_data() { this.$axios.get(`${this.$settings.host}/home/nav/top`) .then((res) => { this.nav_top_list = res.data; }) .catch((error) => { }) }, }, created() { this.get_nav_data(); this.checklogin(); } } </script> <style scoped> .header-cont .nav .active { color: #f5a623; font-weight: 500; border-bottom: 2px solid #f5a623; } .total-header { min-width: 1200px; z-index: 100; box-shadow: 0 4px 8px 0 hsla(0, 0%, 59%, .1); } .header { width: 1200px; margin: 0 auto; } .header .el-header { padding: 0; } .logo { height: 80px; /*line-height: 80px;*/ /*text-align: center;*/ display: flex; /* css3里面的彈性布局,高度設定好之后,設置這個屬性就能讓里面的內(nèi)容居中 */ align-items: center; } .nav .el-row .el-col { height: 80px; line-height: 80px; text-align: center; } .nav a { font-size: 15px; font-weight: 400; cursor: pointer; color: #4a4a4a; text-decoration: none; } .nav .el-row .el-col a:hover { border-bottom: 2px solid #f5a623 } .header-cont { position: relative; } .search input { width: 185px; height: 26px; font-size: 14px; color: #4a4a4a; border: none; border-bottom: 1px solid #ffc210; outline: none; } .search ul { width: 185px; height: 26px; display: flex; align-items: center; padding: 0; padding-bottom: 3px; border-bottom: 1px solid hsla(0, 0%, 59%, .25); cursor: text; margin: 0; font-family: Helvetica Neue, Helvetica, Microsoft YaHei, Arial, sans-serif; } .search .search-ul, .search #Input { padding-top: 10px; } .search ul span { color: #545c63; font-size: 12px; padding: 3px 12px; background: #eeeeef; cursor: pointer; margin-right: 3px; border-radius: 11px; } .hide { display: none; } .search { height: auto; display: flex; } .search p { position: relative; margin-right: 20px; margin-left: 4px; } .search p .icon { width: 16px; height: 16px; cursor: pointer; } .search p .new { width: 18px; height: 10px; position: absolute; left: 15px; top: 0; } .register { height: 36px; display: flex; align-items: center; line-height: 36px; } .register .signin, .register .signup { font-size: 14px; color: #5e5e5e; white-space: nowrap; } .register button { outline: none; cursor: pointer; border: none; background: transparent; } .register a { color: #000; outline: none; } .header-right-box { height: 100%; display: flex; align-items: center; font-size: 15px; color: #4a4a4a; position: absolute; right: 0; top: 0; } .shop-car { width: 99px; height: 28px; border-radius: 15px; margin-right: 20px; background: #f7f7f7; display: flex; align-items: center; justify-content: center; position: relative; cursor: pointer; } .shop-car b { position: absolute; left: 28px; top: -1px; width: 18px; height: 16px; color: #fff; font-size: 12px; font-weight: 350; display: flex; justify-content: center; align-items: center; border-radius: 50%; background: #ff0826; overflow: hidden; transform: scale(.8); } .shop-car img { width: 20px; height: 20px; margin-right: 7px; } .nav-right-box { position: relative; } .nav-right-box .nav-right { float: right; display: flex; height: 100%; line-height: 60px; position: relative; } .nav-right .nav-study { font-size: 15px; font-weight: 300; color: #5e5e5e; margin-right: 20px; cursor: pointer; } .nav-right .nav-study:hover { color: #000; } .nav-img img { width: 26px; height: 26px; border-radius: 50%; display: inline-block; cursor: pointer; } .home-my-account { position: absolute; right: 0; top: 60px; z-index: 101; width: 190px; height: auto; background: #fff; border-radius: 4px; box-shadow: 0 4px 8px 0 #d0d0d0; } li { list-style: none; } .home-my-account li { height: 40px; font-size: 14px; font-weight: 300; color: #5e5e5e; padding-left: 20px; padding-right: 20px; cursor: pointer; display: flex; align-items: center; justify-content: space-between; box-sizing: border-box; } .home-my-account li img { cursor: pointer; width: 5px; height: 10px; } .home-my-account li span { height: 40px; display: flex; align-items: center; } .home-my-account li span b { font-weight: 300; margin-top: -2px; } </style>
導航欄底部組件
lyweb/src/components/common/Footer.vue
<template> <div class="footer"> <div class="footer-item"> <div class="foot-left"> <div class="foot-content"> <p> <span>關(guān)于我們</span> | <span>貝里小賣鋪</span> </p> <p> 地址:...... </p> <p> .......... <a class="copyright" rel="external nofollow" target="_blank" >京ICP備17072161號-1</a> </p> <p> <a class="report-link" target="_blank" rel="external nofollow" > <img class="report-img" src="http://img.alicdn.com/tfs/TB1..50QpXXXXX7XpXXXXXXXXXX-40-40.png" style="float:left" > 京公網(wǎng)安備 11010102002019號 </a> </p> </div> </div> <img src="@/assets/code.png" alt="" class="code"> </div> </div> </template> <script> export default { name: "Footer" } </script> <style scoped> .footer{ display: flex; align-items: center; width: 100%; height: 140px; flex-direction: column; overflow: hidden; background: #191c25; } .footer .foot-left{ display: flex; align-items: center; } .footer .foot-left .foot-content p{ margin-bottom: 10px; font-size: 13px; font-family: PingFangSC-Regular; font-weight: 400; color: #d0d0d0; } .footer-item{ width: 960px; height: 100%; justify-content: space-between; } .foot-left{ display: flex; align-items: center; float: left; } .foot-content a{ color: #d0d0d0; } .footer .foot-left .foot-content p:first-child span{ font-size: 16px; font-weight: 400; display: inline-block; font-family: PingFangSC-Regular; cursor: pointer; } .foot-content .report-img{ display: inline-block; height: 20px; margin-right: 12px; } .footer-item .code{ width: 74px; height: auto; margin-right: 100px; float: right; padding-top: 30px; } </style>
后端導航欄的實現(xiàn)
設計導航欄的model模型類
lyapi/lyapi/apps/home/models.py
class Nav(BaseModel): """導航菜單模型""" POSITION_OPTION = ( (1, "頂部導航"), (2, "腳部導航"), ) title = models.CharField(max_length=500, verbose_name="導航標題") link = models.CharField(max_length=500, verbose_name="導航鏈接") position = models.IntegerField(choices=POSITION_OPTION, default=1, verbose_name="導航位置") is_site = models.BooleanField(default=False, verbose_name="是否是站外地址") class Meta: db_table = 'ly_nav' verbose_name = '導航菜單' verbose_name_plural = verbose_name # 自定義方法[自定義字段或者自定義工具方法] def __str__(self): return self.title
在Xadmin中注冊導航欄模型類
from home import models import xadmin from xadmin import views # 導航欄菜單 class NavXadmin(object): list_display = ['id', 'title', 'link', 'position', 'is_site'] # 注冊Xadmin xadmin.site.register(models.Nav, NavXadmin)
數(shù)據(jù)庫遷移指令
python manage.py makemigrations
python manage.py migrate
在Xadmin中添加一些導航欄數(shù)據(jù)
序列化器
lyapi/apps/home/serializer.py
from rest_framework import serializers from . import models class NavModelSeiralizer(serializers.ModelSerializer): class Meta: model = models.Nav fields = ['id', 'title', 'link', 'is_site']
視圖代碼
lyapi/lyapi/apps/home/views.py
from rest_framework.generics import ListAPIView from . import models from .serializer import BannerModelSeiralizer, NavModelSeiralizer from lyapi.settings import contains class NavTopView(ListAPIView): queryset = models.Nav.objects.filter(is_show=True, is_deleted=False, position=1).order_by('orders')[ 0:contains.NAV_TOP_LENGTH] serializer_class = NavModelSeiralizer
常量配置
lyapi/lyapi/settings/contains.py
# 輪播圖顯示條數(shù) BANNER_LENGTH = 3 # 頂部導航欄顯示個數(shù) NAV_TOP_LENGTH = 6 # 腳部導航的數(shù)量 FOOTER_NAV_LENGTH = 6
路由代碼
lyapi/lyapi/apps/home/urls.py
from django.urls import path, re_path from django.conf import settings from . import views urlpatterns = [ path(r'banner/', views.BannerView.as_view()), path(r'nav/top/', views.NavTopView.as_view()), ]
到此這篇關(guān)于Python輪播圖與導航欄功能的實現(xiàn)流程全講解的文章就介紹到這了,更多相關(guān)Python輪播圖與導航欄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python基于FTP模塊實現(xiàn)ftp文件上傳操作示例
這篇文章主要介紹了Python基于FTP模塊實現(xiàn)ftp文件上傳操作,結(jié)合實例形式分析了Python引入ftp模塊及相關(guān)設置、文件傳輸?shù)炔僮骷记?需要的朋友可以參考下2018-04-04Python中的None與 NULL(即空字符)的區(qū)別詳解
這篇文章主要介紹了Python中的None與 NULL(即空字符)的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09python使用 HTMLTestRunner.py生成測試報告
這篇文章主要介紹了python使用 HTMLTestRunner.py生成測試報告 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10python使用paramiko模塊實現(xiàn)ssh遠程登陸上傳文件并執(zhí)行
使用paramiko,ssh遠程登陸,長傳文件并執(zhí)行。其中用到了多線程和隊列,paramiko是用python語言寫的一個模塊,遵循SSH2協(xié)議,支持以加密和認證的方式,進行遠程服務器的連接。2014-01-01Python3.8如何解決No module named 'numpy&apos
這篇文章主要介紹了Python3.8如何解決No module named 'numpy'報錯問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06基于Python的網(wǎng)頁自動化工具DrissionPage的使用詳解
DrissionPage 是一個基于 python 的網(wǎng)頁自動化工具,它既能控制瀏覽器,也能收發(fā)數(shù)據(jù)包,還能把兩者合而為一,下面就跟隨小編一起來學習一下它的具體使用吧2024-01-01