前臺主頁搭建
vue前端元件開發
components/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>
components/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>
components/Header.vue
<template>
<div class="header">
<div class="slogan">
<p>路飛學城 | 幫助有志向的年輕人通過努力學習獲得體面的工作和生活</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>
components/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號-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應用
startapp home
表設計
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 # 表示它是虛擬的,不在資料庫中生成表,它只用來做繼承
遷移資料,建立超級使用者
命令
# python manage.py makemigrations ---》如果沒有變化,是app沒註冊
# python manage.py migrate
# python manage.py createsuperuser --->建立個使用者
pycharm快捷
引入simpleui,錄入資料
# 下載
pip install django-simpleui
# dev.py註冊app
INSTALLED_APPS = [
'simpleui',
...
]
# 在home/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 = '自定義按鈕'
輪播圖介面格式
格式如下,可以使用自定製的APIResponse
{code:100,msg:成功,result:[{img:地址,link:跳轉地址,orders:順序,title:名字},{img:地址,link:跳轉地址,orders:順序,title:名字}]}
輪播圖介面實現
總路由:urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/home/', include('home.urls')), # http://127.0.0.1:8000/api/v1/home/banner/
]
home路由:urls.py
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)),
]
檢視類
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']
處理跨域請求
同源策略
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現
請求的url地址,必須與瀏覽器上的url地址處於同域上,也就是域名,埠,協議相同,否則,載入回來的資料就會禁止,比如:前端Vue專案是http://127.0.0.1:8080
,後端專案地址http://127.0.0.1:8000
,那麼這倆就屬於不同源,前後端分離,就會遇到這個問題。
瀏覽器上就會報錯,這個就是同源策略的保護,如果瀏覽器對javascript沒有同源策略的保護,那麼一些重要的機密網站將會很危險
但是注意,專案2中的訪問已經發生了,說明是瀏覽器對非同源請求返回的結果做了攔截
CORS(跨域資源共享)簡介
CORS需要瀏覽器和伺服器同時支援。目前,大部分瀏覽器都支援該功能。
整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發者來說,CORS通訊與同源的AJAX通訊沒有差別,程式碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動新增一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。
因此,實現CORS通訊的關鍵是伺服器。只要伺服器實現了CORS介面,就可以跨源通訊,只需要在響應頭中指定,允許跨域即可
比較老的技術比如:jsonp技術,如果出現了跨域問題它可以通過img,script,link
標籤的連線功能,利用js的漏洞執行回撥函式解決
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請求,在響應頭中加入允許
# DRF中使用 Response(result=res.data,headers={"Access-Control-Allow-Origin":"*"})
方式二
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
方式三
使用第三方模組django-cors-headers
-
下載:
pip install django-cors-headers
-
app註冊
INSTALLED_APPS = (
...
'corsheaders',
...
)
- 中介軟體註冊
MIDDLEWARE = [
# Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
...
]
- 配置檔案配置
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'*'
)
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
輪播圖前後端資料互通
settings.js
export default {
base_url: "http://127.0.0.1:8000/api/vi/"
}
banner.vue
<template>
<div class="banner">
<el-carousel :interval="5000" arrow="always" height="400px">
<el-carousel-item v-for="item in banner_list">
<img :src="item.image" alt="">
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: "Banner",
data(){
return {
banner_list:[]
}
},
created() {
this.$axios.get(this.$settings.base_url+'home/banner/').then(res=>{
if(res.data.status==100){
this.banner_list=res.data.result
console.log(this.banner_list)
}
})
}
}
</script>
<style scoped>
el-carousel-item {
height: 400px;
min-width: 1200px;
}
.el-carousel__item img {
height: 400px;
margin-left: calc(50% - 1920px / 2);
}
</style>
後端自定義配置
在setting資料夾下新建 user_settings.py,我們可以把使用者自己的配置放在這個配置檔案中
BANNER_COUNT=3
可以繼續在主配置檔案匯入繼續使用
# 在dev.py中匯入
# 匯入使用者自定義的配置
from .user_settings import *