个人博客Demo: link.
GitHub项目完整链接:link
回顾上一节主要讲了以下2个方面内容:
- 文章详情页面以及评论板块
- 博客的登录与登出
4.1.1 文章管理
- 管理界面的快捷入口在导航栏处
1.新增文章
- new_post.html 代码如下:
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}
{% block title %}新建文章{% endblock title %}
{% block content %}
<div class="page-header">
<h1>新建文章</h1>
</div>
<div>
{{ render_form(form) }}
</div>
{% endblock content %}
{% block scripts %}
{{ super() }}
<script type="text/javascript" src="{{ url_for('static', filename='ckeditor/ckeditor.js')}}"></script>
{{ ckeditor.config(name='body') }}
{% endblock scripts %}
- 上面代码中对{% block script %}追加写入了一个js资源文件,ckeditor.js。这个资源文件用于加载富文本编辑器,对于资源文件包括整个static静态文件文件夹建议到我的github仓库上去下载下来:link,也可以去官方网站下载相应资源文件或用CDN载入
- 新建文章 new_post视图函数代码如下:
新增导入以下模块
from flask import render_template
from Blog.models import Category
from Blog.forms import PostForm
@admin_bm.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
title = form.title.data
body = form.body.data
category = Category.query.get(form.category.data)
post = Post(title=title, body=body, category=category)
db.session.add(post)
db.session.commit()
flash('新文章创建成功!', 'success')
return redirect(url_for('blog.show_post', post_id=post.id))
return render_template('admin/new_post.html', form=form)
- category = Category.query.get(form.category.data)获取category的id值查询到对应分类记录
- 管理文章
- 管理文章页面 manage_post.html代码如下:
{% extends 'base.html' %}
{% from 'bootstrap/pagination.html' import render_pagination %}
{% block title %}文章管理{% endblock title %}
{% block content %}
<div class="page-header">
<h1>
<small class="text-muted">文章共计:{{pagination.total}} 篇</small>
<span class="float-right "><a href="{{ url_for('.new_post')}}" class="btn btn-primary btn-sm">新建</a></span>
</h1>
</div>
{% if posts %}
<table class="table table-striped">
<thead>
<tr>
<th>No.</th>
<th>标题</th>
<th>分类</th>
<th>日期</th>
<th>评论</th>
<th>字数</th>
<th>操作</th>
</tr>
</thead>
{% for post in posts %}
<tr>
<td>{{ loop.index + ((pagination.page - 1) * config.BLOG_MANAGE_POST_PER_PAGE) }}</td>
<td><a href="{{ url_for('blog.show_post', post_id=post.id)}}" class="text-dark">{{ post.title }}</a></td>
<td><a href="{{ url_for('blog.show_category', category_id=post.category.id)}}" class="text-dark">
{{ post.category.name }}</a></td>
<td>{{ moment(post.timestamp).format('LL')}}</td>
<td>{{ post.comments|length }}</td>
<td>{{ post.body|length }}</td>
<td><a class="btn btn-info btn-sm" href="{{ url_for('.edit_post', post_id=post.id) }}">编辑</a>
<form class="inline" method="post"
action="{{ url_for('.delete_post', post_id=post.id, next=request.full_path)}}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('你确定删除此篇文章?'); ">
删除
</button>
</form>
</td>
</tr>
{% endfor %}
</table>
<div class="page-footer">{{ render_pagination(pagination) }}</div>
{% else %}
<div class="tip"><h5>这里一篇文章都没有...</h5></div>
{% endif %}
{% endblock content %}
- 文章管理主页包含新建文章按钮,主要通过表格进行文章的管理,表格中还包含编辑,删除按钮
- 删除操作会修改数据库,为避免CSRF攻击,我们使用表单form元素提交POST请求
- 需要注意的是我们给删除按钮设置一个删除确认弹窗,在< button >标签中添加一个onclick属性,设置一行JS代码:return confirm(),在confirm()参数中传入提示信息作为参数
管理文章页面视图函数manage_post代码:
from flask import request, current_app #新增导入
@admin_bm.route('/post/manage')
@login_required
def manage_post():
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLOG_MANAGE_POST_PER_PAGE']
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=per_page)
posts = pagination.items
return render_template('admin/manage_post.html', pagination=pagination, posts=posts, page=page )
删除文章按钮的视图函数delete_post代码:
@admin_bm.route('post/<int:post_id>/delete', methods=['POST'])
@login_required
def delete_post(post_id):
post = Post.query.get_or_404(post_id)
db.session.delete(post)
db.session.commit()
flash('文章已删除.', 'success')
return redirect_back()
3.编辑文章
- 编辑文章 edit_post.html 代码:
{% extends 'admin/new_post.html' %}
{% from 'bootstrap/form.html' import render_form %}
{% block title %}编辑文章{% endblock title %}
{% block content %}
<div class="page-header">
<h1>编辑文章</h1>
</div>
{{ render_form(form) }}
{% endblock content%}
- 编辑文章按钮 edit_post 视图函数代码:
@admin_bm.route('/post/<int:post_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_post(post_id):
form = PostForm()
post = Post.query.get_or_404(post_id)
if form.validate_on_submit():
post.title = form.title.data
post.category = Category.query.get(form.category.data)
post.body = form.body.data
db.session.commit()
flash('文章已更新!', 'success')
return redirect(url_for('blog.show_post', post_id=post.id))
form.title.data = post.title
form.category.data = post.category_id
form.body.data = post.body
return render_template('admin/edit_post.html', form=form)
- form .title.data = post.title等类似操作是将数据库中原有的该条记录预放置到form表单输入字段,方便编辑修改
4.上传图片设置
- 在admin.py中添加以下视图函数: 用于从本地上传图片到服务器
# 新增导入模块
import os
from Blog.helpers import allowed_file
from flask import send_from_directory
from flask_ckeditor import upload_success, upload_fail
# 获取图片路径
@admin_bm.route('/uploads/<path:filename>')
def get_image(filename):
return send_from_directory(current_app.config['MYBLOG_UPLOAD_PATH'], filename)
# 上传图片
@admin_bm.route('/upload', methods=['POST'])
def upload_image():
# 创建uploads文件夹用于上传图片
folder = os.path.exists(current_app.config['MYBLOG_UPLOAD_PATH'])
if not folder:
os.makedirs(current_app.config['MYBLOG_UPLOAD_PATH'])
# 获取上传对象
f = request.files.get('upload')
# 若不符合规定文件名
if not allowed_file(f.filename):
return upload_fail('Image only!')
f.save(os.path.join(current_app.config['MYBLOG_UPLOAD_PATH'], f.filename))
# 设置图片url规则
url = url_for('.get_image', filename=f.filename)
return upload_success(url, f.filename)
4.1.2 博客设置
- 博客设置的代码相当简单
- 博客设置settings.html 代码如下:
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}
{% block title %}设置{% endblock title%}
{% block content %}
<div class="page-header">
<h1>设置</h1>
</div>
<div>
{{ render_form(form) }}
</div>
{% endblock content %}
- 博客设置settings视图函数代码如下:
# 新增导入模块
from Blog.forms import SettingForm
from flask_login import current_user
@admin_bm.route('/setting', methods=['GET', 'POST'])
@login_required
def settings():
form = SettingForm()
# if和下面代码的顺序不能变
if form.validate_on_submit():
current_user.blog_title = form.blog_title.data
current_user.name = form.name.data
current_user.about = form.about.data
db.session.commit()
flash('博客设置已更新!', 'success')
return redirect(url_for('blog.index'))
form.blog_title.data = current_user.blog_title
form.name.data = current_user.name
form.about.data = current_user.about
return render_template('admin/settings.html', form=form)
下一节将介绍评论管理以及分类管理的内容