新闻管理功能
一、业务功能分析
1.业务需求分析
新闻的增删改查。
2.功能分析
- 新闻列表
- 查询
- 新增
- 修改
二、新闻列表
1.业务流程分析
- 接收参数
- 校验参数
- 查询数据
- 分页
2.接口设计
1.接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/newses/ |
参数格式 | 查询参数 |
2.参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
title | 字符串 | 否 | 要查询的新闻标题 |
tag | 整数 | 否 | 要查询的tag_id |
is_delete | 整数 | 否 | 新闻是否可用 |
page | 整数 | 是 | 父菜单id |
3.返回数据
html
3.后端代码
1.视图
# 在admin/views.py中创建如下视图
class NewsesView(View):
"""
新闻列表视图
url:admin/newses/
"""
def get(self, request):
queryset = News.objects.only('title', 'tag__name', 'author__username', 'is_delete').select_related('tag',
'author').all()
tags = Tag.objects.only('name').filter(is_delete=False)
query_dict = {}
tag_id = request.GET.get('tag')
if tag_id:
query_dict['tag_id'] = tag_id
queryset = queryset.filter(tag_id=tag_id)
title = request.GET.get('title')
if title:
query_dict['title'] = title
queryset = queryset.filter(title__contains=title)
is_delete = request.GET.get('is_delete', None)
flag = False
if is_delete == '0':
is_delete = True
flag = True
if is_delete == '1':
is_delete = False
flag = True
if flag:
queryset = queryset.filter(is_delete=is_delete)
query_dict['is_delete'] = is_delete
paginator = Paginator(queryset, 10)
try:
page = int(request.GET.get('page', 1))
except Exception as e:
page = 1
newses = paginator.get_page(page)
context = {
'newses': newses,
'tags': tags
}
context.update(query_dict)
return render(request, 'myadmin/news/news_list.html', context=context)
2.路由
# 在admin/views.py中添加如下路由
path('newses/', views.NewsesView.as_view(), name='news_list')
4.前端代码
1.html
<!-- 创建 templates/myadmin/news/news_list.html 模板-->
{% extends 'myadmin/base/content_base.html' %}
{% load static %}
{% load news_template_filters %}
{% block page_header %}
系统设置
{% endblock %}
{% block page_option %}
新闻管理
{% endblock %}
{% block content %}
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">新闻列表</h3>
<div class="box-tools">
</div>
</div>
<!-- /.box-header -->
<div class="box-body">
<div style="margin-bottom: 10px">
<form class="form-inline user-query">
<div class="form-group">
<label for="">标题</label>
<input type="text" class="form-control" name="title" value="{{ title }}">
</div>
<div class="form-group">
<label for="">分类</label>
<select name="tag" id="" class="form-control">
<option value="">所有</option>
{% for tag in tags %}
<option {% if tag_id == tag.id %}selected{% endif %}
value="{{ tag.id }}">{{ tag.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="">是否可用</label>
<select name="is_delete" id="" class="form-control">
<option value="2">所有</option>
<option {% if is_delete is False %}selected{% endif %} value="1">是</option>
<option {% if is_delete is True %}selected{% endif %} value="0">否</option>
</select>
</div>
<button type="button" class="btn btn-info query">查询</button>
<button type="button" class="btn btn-default reset">重置</button>
</form>
</div>
<table class="table table-bordered">
<tbody>
<tr>
<th>#</th>
<th>标题</th>
<th>类型</th>
<th>作者</th>
<th>是否可用</th>
</tr>
{% for news in newses %}
<tr>
<td style="width: 40px"><a href="#">{{ forloop.counter }}</a></td>
<td>{{ news.title }}</td>
<td>{{ news.tag.name }}</td>
<td>{{ news.author.username }}</td>
<td>{% if news.is_delete %}否{% else %}是{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 分页 -->
<div class="box-footer clearfix">
<div class="row">
<div class="col-sm-6">
<div class="dataTables_info" id="example2_info" role="status" aria-live="polite">总共:{{ newses.paginator.count }}条 第{{ newses.start_index }}到{{ newses.end_index }}条
</div>
</div>
<div class="col-sm-6">
<ul class="pagination pagination-sm no-margin pull-right">
<li {% if not newses.has_previous %}class="disabled"{% endif %} data-page="{{ newses.number|add:-1 }}"><a href="#">«</a></li>
{% for n in newses|page_bar %}
<li {% if n == newses.number %}class="active" {% endif %} data-page="{{ n }}"><a href="#">{{ n }}</a></li>
{% endfor %}
<li {% if not newses.has_next %}class="disabled"{% endif %} data-page="{{ newses.number|add:1 }}"><a href="#">»</a></li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script src="{% static 'js/myadmin/news/news_list.js' %}"></script>
{% endblock %}
2.js
// 创建 js/myadmin/news/news_list.js
$(() => {
let $queryForm = $('form.user-query'); // 查询表单
let $queryBtn = $('form.user-query button.query'); // 查询按钮
let $resetBtn = $('form.user-query button.reset'); // 重置按钮
// 查询
$queryBtn.click(() => {
$
.ajax({
url: $('.sidebar-menu li.active a').data('url'),
data: $queryForm.serialize(),
type: 'GET'
})
.done((res) => {
$('#content').html(res)
})
.fail(() => {
message.showError('服务器超时,请重试!')
})
});
// 重置
$resetBtn.click(() => {
$queryForm[0].reset();
$
.ajax({
url: $('.sidebar-menu li.active a').data('url'),
type: 'GET'
})
.done((res) => {
$('#content').html(res)
})
.fail(() => {
message.showError('服务器超时,请重试!')
})
});
// 分页 给非
let $pageLi = $('ul.pagination li').not('.active').not('.disabled');
$pageLi.click(function () {
let $this = $(this);
$
.ajax({
url: $('.sidebar-menu li.active a').data('url'),
data: $queryForm.serialize() + '&page=' + $this.data('page'),
type: 'GET'
})
.done((res) => {
$('#content').html(res)
})
.fail(() => {
message.showError('服务器超时,请重试!')
})
});
});
三、新闻详情页
1.业务流程分析
根据提供的新闻id,返回新闻的详细,渲染新闻页面。
这里新闻编写部分,我们引入富文本编辑器。所以,引入django-ckeditor插件
2.django-ckeditor
1.介绍
django-ckeditor是一个集成了富文本编辑器ckeditor的插件,利用它可以在django项目中快速集成富文本编辑器的相关功能。
2.安装配置
1.安装
pip install django-ckeditor
2.配置
在
INSTALLED_APPS
中添加ckeditor
-
在settings.py中添加
STATIC_ROOT
参数,注意,配置项目的静态文件根目录绝对路径例如:STATIC_ROOT = os.path.join(BASE_DIR, 'static')
然后运行命令
python manage.py collectstatic
将ckeditor所需要的静态文件都copy到项目静态文件夹中
-
设置ckeditor所需静态文件路径
# 在settings.py中添加如下配置,注意填写你自己的静态文件路径 CKEDITOR_BASEPATH = "/your_static/ckeditor/ckeditor/"
-
配置ckeditor外观按钮
# 在settings.py中添加如下配置 CKEDITOR_CONFIGS = { 'default': { 'skin': 'moono', # 'skin': 'office2013', 'toolbar_Basic': [ ['Source', '-', 'Bold', 'Italic'] ], 'toolbar_YourCustomToolbarConfig': [ {'name': 'document', 'items': ['Source', '-', 'Save', 'NewPage', 'Preview', 'Print', '-', 'Templates']}, {'name': 'clipboard', 'items': ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']}, {'name': 'editing', 'items': ['Find', 'Replace', '-', 'SelectAll']}, {'name': 'forms', 'items': ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField']}, '/', {'name': 'basicstyles', 'items': ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']}, {'name': 'paragraph', 'items': ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 'Language']}, {'name': 'links', 'items': ['Link', 'Unlink', 'Anchor']}, {'name': 'insert', 'items': ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']}, '/', {'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']}, {'name': 'colors', 'items': ['TextColor', 'BGColor']}, {'name': 'tools', 'items': ['Maximize', 'ShowBlocks']}, {'name': 'about', 'items': ['About']}, '/', # put this to force next toolbar on new line {'name': 'yourcustomtools', 'items': [ # put the name of your editor.ui.addButton here 'Preview', 'Maximize', ]}, ], 'toolbar': 'YourCustomToolbarConfig', # put selected toolbar config here 'tabSpaces': 4, 'extraPlugins': ','.join([ 'uploadimage', # the upload image feature # your extra plugins here 'div', 'autolink', 'autoembed', 'embedsemantic', 'autogrow', # 'devtools', 'widget', 'lineutils', 'clipboard', 'dialog', 'dialogui', 'elementspath' ]), } }
3.上传配置
<span style="color:red">注意:如果需要上传功能,则还需要如下步骤</span>
在
INSTALLED_APPS
中添加ckeditor_uploader
-
在settings.py中添加``CKEDITOR_UPLOAD_PATH
参数,用来指定上传的文件保存目录。这个路径是相对于项目的媒体文件保存目录(MEDIA_ROOT)。例如:
CKEDITOR_UPLOAD_PATH = 'uploads/'
如果使用默认的文件存储系统,那么图片将会被上传到
MEDIA_ROOT
所指定的文件夹下的uploads文件夹中。 -
添加CKEditor URL 到项目根urls.py中
path('ckeditor/', include('ckeditor_uploader.urls')),
-
自定义文件名生成函数
-
在utils文件夹下创建名为ck_uploader的目录,在其下创建funcs.py的脚本内容如下:
import os from hashlib import md5 def get_filename(filename: str) -> str: suffix = filename.split('.')[-1] m = md5(os.urandom(16)+filename.encode('utf-8')) return m.hexdigest() + '.' + suffix if __name__ == '__main__': print(get_filename('aa.txt'))
-
在settings.py中设置
# 设置文件名生成函数 CKEDITOR_FILENAME_GENERATOR = 'utils.ck_uploader.funcs.get_filename'
-
4.接口设计
1. 接口说明
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/news/<int:news_id> |
参数格式 | 路径参数 |
2.参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
news_id | 整数 | 是 | 要查询的新闻id |
3.返回数据
html
5.后端代码
1.模型
# 修改news应用下的News模型中的content字段
from ckeditor_uploader.fields import RichTextUploadingField
from utils.models import BaseModel
class News(BaseModel):
# ...
content = RichTextUploadingField('内容', help_text='内容')
# ...
修改模型之后,记得迁移数据库
2. 表单
# 在admin/forms.py中创建如下表单
from ckeditor_uploader.widgets import CKEditorUploadingWidget
class NewsModelForm(forms.ModelForm):
tag = forms.ModelChoiceField(queryset=None, required=False, help_text='分类', label='分类')
content = forms.CharField(widget=CKEditorUploadingWidget(), label='内容')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['tag'].queryset = Tag.objects.filter(is_delete=False)
class Meta:
model = News
fields = ['title', 'is_delete', 'digest', 'image_url', 'tag', 'content']
3.视图
# 在admin/views.py中添加如下视图
class NewsUpdateView(View):
"""
新闻修改视图
url:/admin/news/<int:news_id>/
"""
def get(self, request, news_id):
# 1. 拿到对应的新闻对象
news = News.objects.filter(id=news_id).first()
if news:
# 2. 生成表单对象
form = NewsModelForm(instance=news)
else:
return json_response(errno=Code.NODATA, errmsg='没有此新闻!')
# 3. 渲染并返回
return render(request, 'myadmin/news/news_detail.html', context={'form': form})
6.前端代码
1.js
// 在js/myadmin/news/news_list.js中添加如下代码
// 实例详情
$('tr').each(function () {
$(this).children('td:first').click(function () {
$('#content').load(
$(this).data('url'),
(response, status, xhr) => {
if (status !== 'success') {
message.showError('服务器超时,请重试!')
}
}
);
})
});
2.html
<!-- 修改 templates/myadmin/news/news_list.html 中for循环的第一个td -->
<td style="width: 40px" data-url="{% url 'admin:update_news' news.id %}"><a href="#">{{ forloop.counter }}</a></td>
<!-- 创建模板 templates/myadmin/news/news_detail.html -->
{% extends 'myadmin/base/content_base.html' %}
{% load static %}
{% load admin_customer_tags %}
{% block page_header %}
系统设置
{% endblock %}
{% block page_option %}
新闻管理
{% endblock %}
{% block content %}
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">新闻详情</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<div class="box-body">
<form class="form-horizontal">
{% csrf_token %}
{% for field in form %}
{% if field.name == 'is_delete' %}
<div class="form-group">
<div class="col-sm-offset-1 col-sm-11">
<div class="checkbox">
<label for="{{ field.id_for_label }}">{{ field }}{{ field.label }}</label>
</div>
</div>
</div>
{% elif field.name == 'image_url' %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label for="{{ field.id_for_label }}"
class="col-sm-1 control-label">{{ field.label }}</label>
<div class="col-sm-11">
<div class="input-group">
{% for error in field.errors %}
<label class="control-label"
for="{{ field.id_for_label }}">{{ error }}</label>
{% endfor %}
{% add_class field 'form-control' %}
<span class="input-group-btn">
<button type="button" class="btn btn-info btn-flat">上传图片</button>
</span>
</div>
</div>
</div>
{% else %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label for="{{ field.id_for_label }}"
class="col-sm-1 control-label">{{ field.label }}</label>
<div class="col-sm-11">
{% for error in field.errors %}
<label class="control-label"
for="{{ field.id_for_label }}">{{ error }}</label>
{% endfor %}
{% add_class field 'form-control' %}
</div>
</div>
{% endif %}
{% endfor %}
{{ form.media }}
</form>
</div>
<div class="box-footer">
<button type="button" class="btn btn-default back">返回</button>
<button type="button" data-url="{% url 'myadmin:user_update' form.instance.id %}"
class="btn btn-primary pull-right save">保存
</button>
</div>
</div>
{% endblock %}
四、新闻封面图片上传
1.接口设计
1.接口说明:
类目 | 说明 |
---|---|
请求方法 | POST |
url定义 | /admin/upload/ |
参数格式 | form表单 |
2.参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
upload | 二进制 | 是 | 上传的图片 |
3.返回数据
json数据
{
"errno": "0",
"errmsg": "ok",
"data":{
"url": "/media/666215aae3d55eaf0c8848a8340174a5.png",
"name": "666215aae3d55eaf0c8848a8340174a5.png",
"uploaded": "1"
}
}
2.后端代码
1.视图
# 在myadmin/views.py中添加如下视图
class UploadFileView(View):
"""
上传文件视图
url:/admin/upload/
"""
def post(self, request):
try:
file = request.FILES['upload']
filename = get_filename(file.name)
file_path = os.path.join(settings.MEDIA_ROOT, filename)
with open(file_path, 'wb') as f:
for chunk in file.chunks():
f.write(chunk)
return json_response(data={
'url': settings.MEDIA_URL + filename,
'name': filename,
'uploaded': '1'
})
except Exception as e:
return json_response(data={'uploaded': '0'})
除了自己写视图之外,还可以直接利用ckeditor_uploader的视图,只需要在前端改url即可。
2.路由
# 在myadmin/urls.py中添加如下路由
path('upload/', views.UploadFileView.as_view(), name='upload')
3.前端代码
1.html
<!-- 修改模板 templates/myadmin/news/news_detail.html 在上传图片的button处添加一个file类型的隐藏input -->
<span class="input-group-btn"><input class="hidden" type="file" >
<button type="button" class="btn btn-info btn-flat">上传图片</button>
</span>
2.js
// 创建 js/myadmin/news/news_detail.js
$(() => {
// 上传封面
// 上传文件input
let $fileInput = $('.input-group-btn input');
let $uploadBtn = $('.input-group-btn button');
$uploadBtn.click(function () {
$fileInput.click()
}
);
// 自动上传文件
$fileInput.change(function () {
$this = $(this);
if ($this.val() !== ''){
let formData = new FormData();
formData.append('upload', $this[0].files[0]);
formData.append('csrfmiddlewaretoken', $('input[name="csrfmiddlewaretoken"]').val());
$
.ajax({
url: '/admin/upload/',
// 使用ckeditor_uploader 就使用下面的url
// url: '/ckeditor/upload/&responseType=json',
type: 'POST',
data: formData,
processData: false,
contentType: false
})
.done((res)=>{
if (res.data.uploaded === '1'){
message.showSuccess('封面图片上传成功!');
$('input[name="image_url"]').val(res.data.url);
// 清空一下
$this.val('')
}else{
message.showError('封面图片上传失败!')
}
})
.fail(()=>{
message.showError('服务器超时, 请重新尝试!')
})
}
});
});
五、新闻更新功能
1.接口设计
1.接口说明:
类目 | 说明 |
---|---|
请求方法 | PUT |
url定义 | /admin/news/<int:news_id>/ |
参数格式 | 路径参数+form表单 |
2.参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
news_id | 整数 | 是 | 需要修改的新闻id |
title | 字符串 | 是 | 需要修改的新闻标题 |
is_delete | 字符串 | 否 | 是否删除新闻 |
digest | 字符串 | 是 | 新闻摘要 |
image_url | 字符串 | 是 | 封面图片url |
tag | 整数 | 是 | 新闻类型 |
content | 字符串 | 是 | 新闻内容 |
3.返回数据
json数据
{
"errno": "0",
"errmsg": "ok",
}
2.后端代码
2.1视图
# 在admin/views.py中的NewsUpdateView视图中添加PUT方法
class NewsUpdateView(View):
"""
新闻更新视图
url:/admin/news/<int:news_id>/
"""
def get(self, request, news_id):
news = News.objects.filter(id=news_id)
if news:
news = news.first()
form = NewsModeForm(instance=news)
else:
form = NewsModeForm()
return render(request, 'admin/news/news_detail.html', context={'form': form})
def put(self, request, news_id):
news = News.objects.filter(id=news_id).first()
put = QueryDict(request.body)
if news:
form = NewsModeForm(put, instance=news)
else:
form = NewsModeForm()
if form.is_valid():
# 优化
# form.save()
if form.has_changed():
instance = form.save(commit=False)
instance.save(update_fields=form.changed_data)
return json_response(errmsg='修改新闻成功!')
else:
return render(request, 'admin/news/news_detail.html', context={
'form': form,
})
2.2其他
因为上传保存的图片url有类似/media/xxxx.jpg
这样的url,直接是用django的内置URL字段类型通不过,所以需要自定义校验器。
# 在utils中创建validators.py文件,编写如下代码
import re
from django.core import validators
class MediaUrlValidator(validators.URLValidator):
def __call__(self, value):
try:
super().__call__(value)
except Exception as e:
if re.match(r'^/media/.*$', value):
pass
else:
raise e
然后修改news/models.py中的News模型中的image_url字段如下
image_url = models.CharField('图片url', max_length=200, default='', help_text='图片url', validators=[MediaUrlValidator()])
3.前端代码
3.1 html
<!-- 修改模板 templates/admin/news/news_detail.html 中保存按钮上的data-url属性 -->
<button type="button" data-url="{% url 'admin:update_news' form.instance.id %}"
class="btn btn-primary pull-right save">保存
</button>
3.2 js
// 更新 js/admin/news/news_detail.js
$(() => {
// 上传封面
// 上传文件input
let $fileInput = $('.input-group-btn input');
let $uploadBtn = $('.input-group-btn button');
$uploadBtn.click(function () {
$fileInput.click()
}
);
// 自动上传文件
$fileInput.change(function () {
$this = $(this);
if ($this.val() !== ''){
let formData = new FormData();
formData.append('upload', $this[0].files[0]);
$
.ajax({
url: '/admin/upload/',
// 使用ckeditor_uploader 就使用下面的url
// url: '/ckeditor/upload/&responseType=json',
type: 'POST',
data: formData,
processData: false,
contentType: false
})
.done((res)=>{
if (res.uploaded === '1'){
message.showSuccess('封面图片上传成功!');
$('input[name="image_url"]').val(res.url);
// 清空一下
$this.val('')
}else{
message.showError('封面图片上传失败!')
}
})
.fail(()=>{
message.showError('服务器超时, 请重新尝试!')
})
}
});
// 返回按钮
$('.box-footer button.back').click(() => {
$('#content').load(
$('.sidebar-menu li.active a').data('url'),
(response, status, xhr) => {
if (status !== 'success') {
message.showError('服务器超时,请重试!')
}
}
);
});
$('.box-footer button.save').click(function () {
// 更新富文本编辑器内容到form表单
window.window.CKEDITOR.instances.id_content.updateElement();
$
.ajax({
url: $(this).data('url'),
data: $('form').serialize(),
type: 'PUT'
})
.done((res) => {
if (res.errno === '0') {
message.showSuccess(res.errmsg);
$('#content').load(
$('.sidebar-menu li.active a').data('url'),
(response, status, xhr) => {
if (status !== 'success') {
message.showError('服务器超时,请重试!')
}
}
);
} else {
$('#content').html(res)
}
})
.fail((res) => {
message.showError('服务器超时,请重试!')
})
})
});
六、添加新闻页面
1.接口设计
1.接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/news/ |
参数格式 | 无参数 |
2.返回数据
返回html
2.后端代码
1.视图
# 在admin/views.py中天添加如下视图
class NewsAddView(View):
"""
新闻添加视图
"""
def get(self, request):
form = NewsModeForm()
return render(request, 'admin/news/news_detail.html', context={'form': form})
2.路由
# 在admin/urls.py中添加如下路由
path('news/', views.NewsAddView.as_view(), name='add_news'),
3.前端代码
1.html
<!-- 在admin/news/news_list.html 模板中,添加添加新闻按钮 -->
...
<div class="box-tools">
<button type="button" class="btn btn-primary btn-sm"
data-url="{% url 'admin:add_news' %}">添加新闻
</button>
</div>
...
2.js
// 在js/admin/news/news_list.js中添加添加新闻按钮的js代码
// 添加新闻
$('.box-tools button').click(function () {
$('#content').load(
$(this).data('url'),
(response, status, xhr) => {
if (status !== 'success') {
message.showError('服务器超时,请重试!')
}
}
);
});
七、添加新闻功能
1.接口设计
1.接口说明:
类目 | 说明 |
---|---|
请求方法 | POST |
url定义 | /admin/news/ |
参数格式 | form表单 |
2.参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
title | 字符串 | 是 | 需要修改的新闻标题 |
is_delete | 字符串 | 否 | 是否删除新闻 |
digest | 字符串 | 是 | 新闻摘要 |
image_url | 字符串 | 是 | 封面图片url |
tag | 整数 | 是 | 新闻类型 |
content | 字符串 | 是 | 新闻内容 |
3.返回数据
成功返回json数据
{
"errno": "0",
"errmsg": "添加新闻成功!",
}
失败返回html
2.后端代码
1.视图
# 在admin/views.py中的NewsAddView视图中添加一下post方法
class NewsAddView(View):
"""
新闻添加视图
"""
def get(self, request):
form = NewsModeForm()
return render(request, 'admin/news/news_detail.html', context={'form': form})
def post(self, request):
form = NewsModeForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return json_response(errmsg='添加新闻成功!')
else:
return render(request, 'admin/news/news_detail.html', context={'form': form})
3.前端代码
1.html
<!-- 在admin/news/news_detail.html 模板中,修改保存按钮 -->
...
<button type="button" {% if form.instance.id %}
data-url="{% url 'admin:update_news' form.instance.id %}"
data-type="PUT"
{% else %}
data-url="{% url 'admin:add_news' %}"
data-type="POST"
{% endif %}
class="btn btn-primary pull-right save">保存
</button>
...
2.js
// 修改js/admin/news/news_detail.js中响应点击保存按钮后的js代码如下
$('.box-footer button.save').click(function () {
// 更新富文本编辑器内容到form表单
window.window.CKEDITOR.instances.id_content.updateElement();
$
.ajax({
url: $(this).data('url'),
data: $('form').serialize(),
type: $(this).data('type')
})
.done((res) => {
if (res.errno === '0') {
message.showSuccess(res.errmsg);
$('#content').load(
$('.sidebar-menu li.active a').data('url'),
(response, status, xhr) => {
if (status !== 'success') {
message.showError('服务器超时,请重试!')
}
}
);
} else {
$('#content').html(res)
}
})
.fail((res) => {
message.showError('服务器超时,请重试!')
})
})