后台管理站点 -- 5.轮播图管理
2019-03-13 本文已影响0人
爱修仙的道友
原理同 热门文章管理
- views.py
class BannerManageView(PermissionRequiredMixin, View):
permission_required = ('news.view_banner', )
raise_exception = True
def get(self, request):
priority_dict = OrderedDict(models.Banner.PRI_CHOICES)
banners = models.Banner.objects.only('image_url', 'priority').filter(is_delete=False)
return render(request, 'admin/news/news_banner.html', locals())
class BannerEditView(PermissionRequiredMixin, View):
permission_required = ('news.delete_banner', 'news.change_banner')
raise_exception = True
def handle_no_permission(self):
if self.request.method.lower() != 'get':
return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
else:
return super(BannerEditView, self).handle_no_permission()
def delete(self, request, banner_id):
banner = models.Banner.objects.only('id').filter(id=banner_id).first()
if banner:
banner.is_delete = True
banner.save(update_fields=['is_delete'])
return to_json_data(errmsg="轮播图删除成功")
else:
return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的轮播图不存在")
def put(self, request, banner_id):
banner = models.Banner.objects.only('id').filter(id=banner_id).first()
if not banner:
return to_json_data(errno=Code.PARAMERR, errmsg="需要更新的轮播图不存在")
json_data = request.body
if not json_data:
return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
# 将json转化为dict
dict_data = json.loads(json_data.decode('utf8'))
try:
priority = int(dict_data.get('priority'))
priority_list = [i for i, _ in models.Banner.PRI_CHOICES]
if priority not in priority_list:
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图的优先级设置错误')
except Exception as e:
logger.info('轮播图优先级异常:\n{}'.format(e))
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图的优先级设置错误')
image_url = dict_data.get('image_url')
if not image_url:
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图url为空')
if banner.priority == priority and banner.image_url == image_url:
return to_json_data(errno=Code.PARAMERR, errmsg="轮播图的参数未改变")
banner.priority = priority
banner.image_url = image_url
banner.save(update_fields=['priority', 'image_url'])
return to_json_data(errmsg="轮播图更新成功")
class BannerAddView(PermissionRequiredMixin, View):
permission_required = ('news.delete_banner', 'news.change_banner', 'news.view_banner')
raise_exception = True
def handle_no_permission(self):
if self.request.method.lower() != 'get':
return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
else:
return super(BannerAddView, self).handle_no_permission()
def get(self, request):
tags = models.Tag.objects.values('id', 'name').annotate(num_news=Count('news')). \
filter(is_delete=False).order_by('-num_news', 'update_time')
# 优先级列表
# priority_list = {K: v for k, v in models.Banner.PRI_CHOICES}
priority_dict = OrderedDict(models.Banner.PRI_CHOICES)
return render(request, 'admin/news/news_banner_add.html', locals())
def post(self, request):
json_data = request.body
if not json_data:
return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
# 将json转化为dict
dict_data = json.loads(json_data.decode('utf8'))
try:
news_id = int(dict_data.get('news_id'))
except Exception as e:
logger.info('前端传过来的文章id参数异常:\n{}'.format(e))
return to_json_data(errno=Code.PARAMERR, errmsg='参数错误')
if not models.News.objects.filter(id=news_id).exists():
return to_json_data(errno=Code.PARAMERR, errmsg='文章不存在')
try:
priority = int(dict_data.get('priority'))
priority_list = [i for i, _ in models.Banner.PRI_CHOICES]
if priority not in priority_list:
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图的优先级设置错误')
except Exception as e:
logger.info('轮播图优先级异常:\n{}'.format(e))
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图的优先级设置错误')
# 获取轮播图url
image_url = dict_data.get('image_url')
if not image_url:
return to_json_data(errno=Code.PARAMERR, errmsg='轮播图url为空')
# 创建轮播图
banners_tuple = models.Banner.objects.get_or_create(news_id=news_id)
banner, is_created = banners_tuple
banner.priority = priority
banner.image_url = image_url
banner.save(update_fields=['priority', 'image_url'])
return to_json_data(errmsg="轮播图创建成功")
- urls.py
path('banners/', views.BannerManageView.as_view(), name='banners_manage'),
path('banners/<int:banner_id>/', views.BannerEditView.as_view(), name='banners_edit'),
path('banners/add/', views.BannerAddView.as_view(), name='banners_add'),
- html.py
<!-- 创建templates/admin/news/news_banner.html文件 -->
{% extends 'admin/base/base.html' %}
{% block title %}
添加 banner
{% endblock %}
{% block content_header %}
添加 banner
{% endblock %}
{% block header_option_desc %}
添加 banner
{% endblock %}
{% block content %}
<style>
.banner-img {
width: 328px;
height: 82px;
}
.banner-img img {
width: 100%;
max-height: 100%;
}
.banner-info {
margin-left: 20px;
}
.form-group {
width: 500px;
}
ul.banner-list{
list-style:none;
margin:0;
padding:0;
}
ul.banner-list li.banner-item{
margin-top: 20px;
}
@media screen and (max-width: 1100px) {
.form-group {
margin-top: 15px;
}
.banner-info {
margin: 0;
}
}
</style>
<div class="row">
<div class="col-lg-6">
<button class="btn btn-primary pull-left" id="banner-add-btn"><i class="fa fa-plus"></i> 添加轮播图</button>
<ul class="pull-left tips" style="line-height: 18px;">
<li>支持 JPG/PNG 格式的图片 最多可上传6张</li>
<li>图片的宽度最好在800px以上,比例为4:1</li>
</ul>
</div>
</div>
<ul class="banner-list">
{% for one_banner in banners %}
<li class="box banner-item box-primary" data-banner-id="{{ one_banner.id }}">
<div class="box-header">
<span>当前优先级为:<span class="priority-number">{{ one_banner.priority }}</span></span>
<a href="javascript:void(0);" class="btn btn-danger btn-xs pull-right close-btn">
<i class="fa fa-close"></i>
</a>
</div>
<div class="box-body">
<div class="pull-left banner-img">
<input type="file" name="banner-image-select" style="display: none;">
<img src="{{ one_banner.image_url }}" class="img-thumbnail banner-image">
</div>
<div class="pull-left banner-info">
<div class="form-group">
<label for="priority" class="control-label" style="margin-bottom: 10px">选择优先级(第一级最高):</label>
<div>
<select name="priority" id="priority" class="form-control">
<option value="0">--请选择优先级--</option>
{% for id, value in priority_dict.items %}
{% if id == one_banner.priority %}
<option value="{{ id }}" selected>{{ value }}</option>
{% else %}
<option value="{{ id }}">{{ value }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
</div>
</div>
<div class="box-footer">
<button class="btn btn-primary pull-right update-btn" data-image-url="{{ one_banner.image_url }}"
data-priority="{{ one_banner.priority }}">更新
</button>
</div>
</li>
{% endfor %}
</ul>
{% endblock %}
{% block script %}
<script src="/static/js/admin/news/news_banner.js"></script>
{% endblock %}
// 创建static/js/admin/news/news_banner.js文件
$(function () {
let $closeBtn = $('.close-btn'); // 删除轮播图按钮
let $bannerList = $(".banner-list");
let $updateBtn = $(".update-btn"); // 保存按钮
let $bannerAddBtn = $("#banner-add-btn"); // 添加轮播图按钮
let $bannerImage = $(".banner-image"); // 获取图片元素
let $bannerImageSelect = $('input[name=banner-image-select]'); // image input元素
// 删除轮播图
$closeBtn.click(function () {
let _this = this;
let sBannerId = $(this).parents('li').data("banner-id");
fAlert.alertConfirm({
"title": "删除轮播图",
"type": "error",
"confirmText": "确认",
"confirmCallback": function () {
$.ajax({
// 请求地址
url: "/admin/banners/" + sBannerId + "/", // url尾部需要添加/
// 请求方式
type: "DELETE",
dataType: "json",
})
.done(function (res) {
if (res.errno === "200") {
message.showSuccess("标签删除成功");
$(_this).parents('li').remove();
} else {
message.showError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
}
})
});
// 更新轮播图
$updateBtn.click(function () {
// let _this = this;
let imageUrl = $(this).parents('li').find('.banner-image').attr("src");
let priority = $(this).parents('li').find('#priority').val();
let bannerId = $(this).parents('li').data("banner-id");
// 未更新之前的原始值
let sSrcPriority = $(this).data('priority'); // 未更新之前的优先级
let sImageUrl = $(this).data('image-url'); // 未更新之前的图片url
if (!imageUrl) {
message.showError('轮播图url为空');
return
}
if (priority == sSrcPriority && imageUrl === sImageUrl) {
message.showError('未修改任何值');
return
}
let sDataParams = {
"image_url": imageUrl,
"priority": priority,
"banner_id": bannerId
};
$.ajax({
// 请求地址
url: "/admin/banners/" + bannerId + "/", // url尾部需要添加/
// 请求方式
type: "PUT",
data: JSON.stringify(sDataParams),
// 请求内容的数据类型(前端发给后端的格式)
contentType: "application/json; charset=utf-8",
// 响应数据的格式(后端返回给前端的格式)
dataType: "json",
})
.done(function (res) {
if (res.errno === "200") {
message.showSuccess("更新成功");
// fAlert.alertSuccessToast("更新成功");
setTimeout(function () {
window.location.href = '/admin/banners/';
}, 900)
} else {
swal.showInputError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// 上传轮播图片
$bannerImage.click(function () {
$(this).prev().click();
});
$bannerImageSelect.change(function () {
let _this = this;
// 获取文件对象
let file = this.files[0]; // 获取文件
let oFormData = new FormData(); // 创建一个 FormData
oFormData.append("image_file", file); // 把文件添加进去
// 发送请求
$.ajax({
url: "/admin/news/images/",
method: "POST",
data: oFormData,
processData: false, // 定义文件的传输
contentType: false,
})
.done(function (res) {
if (res.errno === "200") {
let sImageUrl = res["data"]["image_url"];
$(_this).next().attr('src', sImageUrl);
} else {
message.showError(res.errmsg)
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// 添加轮播图
$bannerAddBtn.click(function () {
if ($bannerList.find('li').length < 6) {
window.location.href = '/admin/banners/add/';
} else {
message.showError("最多只能添加6个轮播图")
}
});
// get cookie using jQuery
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// Setting the token on the AJAX request
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
});
<!-- 创建templates/admin/news/news_banner_add.html文件 -->
{% extends 'admin/base/base.html' %}
{% block title %}
添加轮播图
{% endblock %}
{% block content_header %}
添加轮播图
{% endblock %}
{% block header_option_desc %}
添加轮播图
{% endblock %}
{% block content %}
<style>
.banner-img {
width: 40%;
margin: 10px 300px 20px;
}
.banner-img img {
width: 100%;
max-height: 100%;
}
@media screen and (max-width: 1100px) {
.form-group {
margin-top: 15px;
}
}
</style>
<div class="box box-primary">
<div class="box-body">
<div class="form-horizontal">
<div class="form-group">
<div class="pull-left banner-img">
<input type="file" name="banner-image-select" style="display: none;">
<img src="" class="img-thumbnail banner-image">
</div>
</div>
<div class="form-group">
<label for="category-select" class="col-md-2 col-sm-2 control-label">选择文章分类</label>
<div class="col-md-2 col-sm-3">
<select name="category" id="category-select" class="form-control input-md">
<option value="0">--请选择文章分类--</option>
{% for one_tag in tags %}
<option value="{{ one_tag.id }}">{{ one_tag.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-8 col-sm-7">
<label for="news-select" style="display: none;"></label>
<select name="news" class="form-control input-md" id="news-select">
<option value="0">--请选择文章--</option>
</select>
</div>
</div>
<div class="form-group">
<label for="priority" class="col-md-2 col-sm-2 control-label">选择优先级</label>
<div class="col-md-2 col-sm-3">
<select name="priority" id="priority" class="form-control input-md">
<option value="0">--请选择优先级--</option>
{% for id, value in priority_dict.items %}
<option value="{{ id }}">{{ value }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="box-footer">
<a href="javascript:void(0);" class="btn btn-primary pull-right" id="save-btn">保存</a>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script src="/static/js/admin/news/news_banner_add.js"></script>
{% endblock %}
// 创建static/js/admin/news/news_banner_add.js文件
$(function () {
let $tagSelect = $("#category-select"); // 获取选择分类标签元素
let $newsSelect = $("#news-select"); // 获取选择文章标签元素
let $saveBtn = $('#save-btn'); // 获取保存按钮元素
let $bannerImage = $(".banner-image"); // 获取图片元素
let $bannerImageSelect = $('input[name=banner-image-select]'); // image input元素
// 上传轮播图片
$bannerImage.click(function () {
$(this).prev().click();
});
$bannerImageSelect.change(function () {
let _this = this;
// 获取文件对象
let file = this.files[0]; // 获取文件
let oFormData = new FormData(); // 创建一个 FormData
oFormData.append("image_file", file); // 把文件添加进去
// 发送请求
$.ajax({
url: "/admin/news/images/",
method: "POST",
data: oFormData,
processData: false, // 定义文件的传输
contentType: false,
})
.done(function (res) {
if (res.errno === "200") {
let sImageUrl = res["data"]["image_url"];
$(_this).next().attr('src', sImageUrl);
} else {
message.showError(res.errmsg)
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// 选择文章不同类别,获取相应的文章
$tagSelect.change(function () {
// 获取当前选中的下拉框的value
let sTagId = $(this).val();
if (sTagId === '0') {
$newsSelect.children('option').remove();
$newsSelect.append(`<option value="0">--请选择文章--</option>`);
return
}
// 根据文章分类id向后端发起get请求
$.ajax({
// 请求地址
url: "/admin/tags/" + sTagId + "/news/", // url尾部需要添加/
// 请求方式
type: "GET",
dataType: "json",
})
.done(function (res) {
if (res.errno === "200") {
$newsSelect.children('option').remove();
$newsSelect.append(`<option value="0">--请选择文章--</option>`);
res.data.news.forEach(function (one_news) {
let content = `<option value="${one_news.id}">${one_news.title}</option>`;
$newsSelect.append(content)
});
} else {
// swal.showInputError(res.errmsg);
fAlert.alertErrorToast(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
});
// 点击保存按钮执行的事件
$saveBtn.click(function () {
let priority = $("#priority").val(); // 获取优先级
// 获取下拉框中选中的文章标签id 和 文章id
let sTagId = $tagSelect.val();
let sNewsId = $newsSelect.val();
let sImageUrl = $bannerImage.attr('src');
// 打印值
console.log(`
priority(优先级): ${priority}
tagsTagId(文章标签id): ${sTagId}
sNewsId(文章id): ${sNewsId}
sImageUrl(轮播图url): ${sImageUrl}
`);
if (sImageUrl === '/static/images/banner_default.png') {
message.showError('轮播图不能为默认图片');
return
}
// 判断是否为 0, 表示在第一个 未选择
if (sTagId !== '0' && sNewsId !== '0' && priority !== '0' && sImageUrl) {
let sDataParams = {
"priority": priority,
"news_id": sNewsId,
"image_url": sImageUrl
};
$.ajax({
// 请求地址
url: "/admin/banners/add/", // url尾部需要添加/
// 请求方式
type: "POST",
data: JSON.stringify(sDataParams),
// 请求内容的数据类型(前端发给后端的格式)
contentType: "application/json; charset=utf-8",
// 响应数据的格式(后端返回给前端的格式)
dataType: "json",
})
.done(function (res) {
if (res.errno === "200") {
message.showSuccess("轮播图创建成功");
setTimeout(function () {
window.location.href = '/admin/banners/';
}, 800)
} else {
message.showError(res.errmsg);
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
} else {
message.showError("文章分类、文章以及优先级都要选!");
}
});
// get cookie using jQuery
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// Setting the token on the AJAX request
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
});