1 后台主页模块设计
# 首页需要写的接口分析
1.轮播图接口 (以它为例)
2.6个推荐课程接口
3.老师接口
# 建一个首页app:home
python ../../manage.py startapp home
# 轮播图接口
-轮播图表---》运营从后台把图片上传
-图片名称,图片地址,跳转链接,描述
-上传日期,更新日期,图片排序,是否删除(软删除),是否展示
-迁移(把app注册)
-查询所有轮播图接口
# 配置开启,media
# 移动端,开启app广告功能(实质就几张录播图片及跳转链接)
-img:真正的图片
-link_type:self 或 outer # 跳转类型:内部还是外部
# 前端根据这个,自己决定本窗口跳转还是打开新窗口跳转
-link: /Home 或 http://www.baidu.com
后台录入功能:(前后端分离的,需要再写一个广告的录入接口)
-录入接口
1.1 创建基表
from django.db import models
# 只用来继承,不在数据库生成
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 #只用来继承,不在数据库生成
1.2 创建home,app,在models下写Banner表
from utils.model import BaseModel
class Banner(BaseModel):
title = models.CharField(max_length=16, unique=True, verbose_name='名称')
image = models.ImageField(upload_to='banner', verbose_name='图片') # 图片的访问地址
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
#### 先注册home,再迁移表
1.3 写查询所有图片接口
# 1 写序列化类
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = models.Banner
fields = ['title','link','image']
# 2 写视图类
from . import models
from . import serializer
from django.conf import settings
class BannerView(ViewSetMixin, ListAPIView):
queryset = models.Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNT]
serializer_class = serializer.BannerSerializer
# 3 配置路径(路由分发)
# 总路由
path('api/v1/home/', include('home.urls')),
# home的app下新建urls.py
router = SimpleRouter()
router.register('banner', views.BannerView, 'banner')
urlpatterns = [
# path('', include(router.urls)),
]
urlpatterns += router.urls
1.4 自定义用户配置文件
# 在setting文件夹下新建user_setting.py
# 轮播图显示的条数
BANNER_COUNT = 4
# 在项目配置文件dev.py中导入user_setting
from .user_setting import *
# 配置文件中
# 开启media路径
MEDIA_ROOT=os.path.join(BASE_DIR,'media') # 开启的路径
MEDIA_URL = '/media/' # 访问的路径
# 在路由中
from django.views.static import serve
# 配置开启media
# re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
# 上传文件:传到media文件夹下,表字段的upload_to参数文件夹下
# 访问文件:http://127.0.0.1:8000/media/xx/xx.p
2 跨域问题及解决(*****
)
# 1 跨域问题出现的原因? PC端网站前后端分离才会出现 (前后端处于不同的端口上 8080和8000)
-浏览器:同源策略,浏览器的基本安全策略,不允许去不同的url地址获取数据;即域名,端口,协议必须相同
http://127.0.0.1:8080
-访问实质是可以的,只是返回的数据被浏览器拦截,不接受而已
# 2 CORS:后端技术,跨域资源共享,服务端在响应头中加入一下东西,允许跨域
# 3 CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
# 4 符合以下条件,都是简单请求
(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
# 如果Content-Type是json格式,都是非简单请求
# 区别:简单请求只发一次,非简单请求发送两次,第一次是OPTIONS预检请求,第二次是真正的请求
# 5 后端使用cors处理跨域问题
# 5.1 简单请求,支持跨域
-在响应头中设置:Access-Control-Allow-Origin = '域名' 或 '*'
# 5.2 非简单请求支持跨域
-在响应头中设置:Access-Control-Allow-Methods='*'
-在响应头中设置:Access-Control-Allow-Headers='*'
# 自己处理跨域,跟web框架无关
# 写一个中间件
class CorsMiddle(MiddlewareMixin):
def process_response(self, request, response):
# 处理非简单请求
if request.method == 'OPTIONS':
response['Access-Control-Allow-Headers'] = '*'
response['Access-Control-Allow-Methods'] = '*'
# 处理简单请求
response['Access-Control-Allow-Origin'] = '*'
return response
# 中间件配置
# 6 使用第三方,解决跨域
1 安装
pip install django-cors-headers
2 在app中注册
INSTALLED_APPS = (
...
'corsheaders',
...
)
3 在中间件中加入
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]
4 在配置文件中配置
CORS_ALLOW_CREDENTIALS = True # 允许携带Cookie
CORS_ORIGIN_ALLOW_ALL = True # 允许所有域
CORS_ORIGIN_WHITELIST = ( # 允许域的白名单
'http://localhost:8080',
# django-cors-headers版本影响白名单写法,版本包小于3.0不用加http,版本包大于3.0则需要加http
)
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',
'token',
)
3 simple-ui后台管理
# 项目:
-主站:互联网用户,前后端分离
-后台管理:运营,领导...,前后端混合,使用admin
-simple-ui 美化admin
# 集成simpleui
# 创建超级用户
python manage.py createsuperuser
# 录入数据
# 了解:simple-ui是vue+elementui开发的
-基于simpleui二次开发
4 路飞前台首页
# 三个组件:头部,轮播图,尾部
# Home组件中引入
# Banner轮播图和后台接口对接完成,实现跳转
# 前端存数据的地方:
# 1.cookie:有过期时间,借助第三方 vue-cookies
.set(key,value)
.get(key)
# 2.sessionStorage:临时存储,页面关闭就没了
sessionStorage.name = 'lqz';
# 3.localStorage:永久存储,除非客户清理
localStorage.age='19'
<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>
4.2 Banner组件
<template>
<div class="banner">
<el-carousel height="400px">
<el-carousel-item v-for="item in banner_list" :key="item">
<div v-if="item.link.startsWith('http')">
<a :href="item.link"><img :src="item.image" :alt="item.title"></a>
</div>
<div v-else>
<router-link :to="item.link"><img :src="item.image" :alt="item.title"></router-link>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: "Header",
data() {
return {
banner_list: []
}
},
created() {
this.$http.get(this.$settings.base_url + 'home/banner/').then(res => {
this.banner_list = res.data
})
}
}
</script>
<style scoped>
.el-carousel__item {
height: 400px;
min-width: 1200px;
}
.el-carousel__item img {
height: 400px;
margin-left: calc(50% - 1920px / 2);
}
</style>
<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>
补充
1.xss、csrf、cors的区别
# xss: 跨站脚本攻击
恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页面时,
嵌入Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
# csrf: 跨站请求伪造
解决csrf攻击:服务器会给网站返回一个隐藏的随机字符串,第三方网站并不能获取到该字符串,
请求来时,服务器会验证cookies以及该字符串(证明是由正确的网站发的请求)
# cors: 跨域资源共享
是浏览器的同源策略,浏览器的基本安全策略,不允许去不同的url地址获取数据;即域名,端口,协议必须相同