Python Flask搭建个人博客详细回顾—(4.2 博客后台管理)

个人博客Demo: link.
GitHub项目完整链接:link


回顾上一节主要讲了以下2个方面内容:

  • 博客文章管理,包括新建文章,编辑文章,删除文章,文章管理界面,图片上传设置
  • 博客设置

4.2.1 评论管理

  1. 关闭/开启评论功能删除评论功能已经在介绍文章详情页时介绍过,不再赘述

  2. 评论审核查看评论筛选

    a. 对于新的评论,在登录时的导航栏也会有new提示和未读数量提示在评论表格操作页添加一个已读按钮,如果评论的reviewed字段为False,则显示“已读”按钮,并将该行评论以橙色背景显示
    b. 我们将评论分为三类:所有评论,未读评论和管理发布的评论。使用查询参数filter传入筛选的评论类型,这三个类型分别用all,unread和admin表示
    c. 因为这个"已读"操作也会修改数据因此使用form表单元素提交POST请求,manage_comment.html代码如下:

{% extends 'base.html' %}
{% from 'bootstrap/pagination.html' import render_pagination %}

{% block title %}管理评论{% endblock %}

{% block content %}
    <div class="page-header">
        <h1>评论数:
            <small class="text-muted">{{ pagination.total }}</small>
        </h1>

        <!-- 设置评论筛选过滤导航栏 -->
        <ul class="nav nav-pills">
            <li class="nav-item">
                <a class="nav-link disabled" href="#">Filter </a>
            </li>
            <li class="nav-item">
                <!-- request.args.get('filter', 'all')获取查询参数filter -->
                <a class="nav-link {% if request.args.get('filter', 'all') == 'all' %}active{% endif %}"
                   href="{{ url_for('admin.manage_comments', filter='all') }}">全部</a>
            </li>
            <li class="nav-item">
                <a class="nav-link {% if request.args.get('filter') == 'unread' %}active{% endif %}"
                   href="{{ url_for('admin.manage_comments', filter='unread') }}">未读 {% if unread_comments %}
                    <!-- 设置未读评论徽章 -->
                    <span class="badge badge-success">{{ unread_comments }}</span>{% endif %}</a>
            </li>
            <li class="nav-item">
                <a class="nav-link {% if request.args.get('filter') == 'admin' %}active{% endif %}"
                   href="{{ url_for('admin.manage_comments', filter='admin') }}">管理员</a>
            </li>
        </ul>
    </div>

    {% if comments %}
        <table class="table table-striped">
            <thead>
            <tr>
                <th>No.</th>
                <th>作者</th>
                <th>来自文章</th>
                <th>内容</th>
                <th>日期</th>
                <th>操作状态</th>
            </tr>
            </thead>
            {% for comment in comments %}
                <!-- 如果comment未审核,则table表格颜色为warning黄色 -->
                <tr {% if not comment.reviewed %}class="table-warning" {% endif %}>
                    <td>{{ loop.index + ((pagination.page - 1) * config['BLOG_MANAGE_COMMENT_PER_PAGE']) }}</td>
                    <td>
                        <!-- 显示评论作者名及来源url -->
                        {% if comment.from_admin %}{{ admin.name }}{% else %}{{ comment.author }}{% endif %}<br>
                        <!-- 管理员评论徽章 -->
                        {% if comment.from_admin %}
                            <span class="badge badge-primary">Author</span>
                        {% endif %}
                    </td>
                    <td>{{ comment.post.title }}</td>
                    <td>{{ comment.body }}</td>
                    <td>{{ moment(comment.timestamp).format('LL') }}</td>
                    <td>
                        <!-- 未审核添加approve审核标签 -->
                        {% if not comment.reviewed %}
                            <form class="inline" method="post"
                                  action="{{ url_for('.approve_comments', comment_id=comment.id, next=request.full_path) }}">
                                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
                                <button type="submit" class="btn btn-success btn-sm">已读</button>
                            </form>
                        {% endif %}
                        <form class="inline" method="post"
                              action="{{ url_for('.delete_comments', comment_id=comment.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('Are you sure?');">删除
                            </button>
                        </form>
                    </td>
                </tr>
            {% endfor %}
        </table>
        <div class="page-footer">{{ render_pagination(pagination) }}</div>
    {% else %}
        <div class="tip"><h5>这里一条评论也没有...</h5></div>
    {% endif %}
{% endblock %}

管理评论页面视图函数 manage_comments代码如下:

@admin_bm.route('/comment/manages')
@login_required
def manage_comments():
    filter_rule = request.args.get('filter', 'all')  # 从查询字符串获取过滤规则
    page = request.args.get('page', 1, type=int)

    if filter_rule == 'unread':
        filtered_comments = Comment.query.filter_by(reviewed=False)
    elif filter_rule == 'admin':
        filtered_comments = Comment.query.filter_by(from_admin=True)
    else:
        filtered_comments = Comment.query

    # 筛选后的实例化对象进行排序
    pagination = filtered_comments.order_by(Comment.timestamp.desc()).paginate(
        page, per_page=current_app.config['BLOG_MANAGE_COMMENT_PER_PAGE'])
    comments = pagination.items

    return render_template('admin/manage_comments.html',  pagination=pagination, comments=comments)
  • 视图函数中通过获取查询参数"filter"(默认值为all),返回筛选过后的(filter_by)Comment对象,然后分页对象在筛选过后的评论基础之上进行处理,最后渲染模板传递到manage_comments.html中

审核查看评论approve_comments视图函数代码:

@admin_bm.route('/comment/<int:comment_id>/approve', methods=['POST'])
@login_required
def approve_comments(comment_id):
    comment = Comment.query.get_or_404(comment_id)
    comment.reviewed = True
    db.session.commit()
    flash('评论已读', 'success')
    return redirect_back()

4.2.2 分类管理

新增分类

  • 新增分类 new_category,html 代码:
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}

{% block title %}新建分类{% endblock %}

{% block content %}
    <div class="page-header">
        <h1>新建分类</h1>
    </div>
    <div>
        {{ render_form(form) }}
    </div>
{% endblock content %}
  • 新增分类 new_category视图函数代码:
新增导入模块
from Blog.forms import CategoryForm

admin_bm.route('/category/new', methods=['GET', 'POST'])
@login_required
def new_category():
    form = CategoryForm()

    if form.validate_on_submit():
        name = form.name.data
        category = Category(
            name=name
        )
        db.session.add(category)
        db.session.commit()
        flash("新建分类成功!", 'success')
        return redirect(url_for('.manage_category'))
    return render_template('admin/new_category.html', form=form)

分类管理页面

  • 分类管理页面 manage_categroy.html代码:
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_form %}

{% block title %}分类管理{% endblock title %}

{% block content %}
<div class="page-header">
    <h1 ><small class="text-muted">分类共:{{ categories|length }} 个</small>
    <span class="float-right">
        <a class="btn btn-primary btn-sm" href="{{ url_for('.new_category')}}">新建</a>
    </span>
    </h1>
</div>
<table class="table table-striped">
    <thead>
    <tr>
        <th>No.</th>
        <th>分类名</th>
        <th>文章数</th>
        <th>操作</th>
    </tr>
    </thead>
    {% for category in categories %}
    <tr>
        <td>{{ loop.index }}</td>
        <td><a href="{{ url_for('blog.show_category', category_id=category.id)}}">{{ category.name }}</a></td>
        <td>{{ category.posts|length }}</td>
        <!-- 除默认第一个默认分类外都添加Edit和Delete按钮,设置到删除总是采用POST方法,防范CSRF攻击 -->
        <td>
            {% if category.id != 1 %}
            <a class="btn btn-info btn-sm" href="{{ url_for('.edit_category', category_id=category.id)}}">编辑</a>

            <form class="inline" method="post" action="{{ url_for('.delete_category', category_id=category.id)}}">
                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
                <button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('确定删除此分类?');">
                    删除
                </button>
            </form>
        </td>
        {% endif %}
    </tr>
    {% endfor %}
</table>
<p class="text-muted">Tips: 删除分类不会删除分类下的文章,相关文章将会移动到默认分类之中。

</p>
{% endblock content %}
  • 分类管理页面manage_category视图函数代码:
@admin_bm.route('/category/manage')
@login_required
def manage_category():
    return render_template('admin/manage_category.html')

编辑分类

  • 编辑分类edit_category.html代码
{% extends 'base.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_category 视图函数代码: 其中默认分类不能更改,设置flash提醒
@admin_bm.route('/category/<int:category_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_category(category_id):
    form = CategoryForm()
    category = Category.query.get_or_404(category_id)
    # 默认分类不能更改
    if category_id == 1:
        flash('你不能修改默认分类', 'warning')
        return redirect(url_for('blog.index'))
    if form.validate_on_submit():
        category.name = form.name.data
        db.session.commit()
        flash('分类更新成功!', 'success')
        return redirect(url_for('.manage_category'))

    form.name.data = category.name
    return render_template('admin/edit_category.html', form=form)

删除分类

  • 删除分类,其中默认分类不能删除,删除分类只删除分类名,分类下所有文章移动到默认分类中。
  • Blog/models.py数据库模型文件中的Category类中定义delete方法,用于删除分类而将分类下文章移动到默认分类中
  • Category模型类中添加delete()方法:
    def delete(self):
        default_category = Category.query.get(1)  # 获取默认分类
        posts = self.posts[:]	# 将删除分类下所有文章复制到posts变量中
        for post in posts:
            post.category = default_category	# 将post分类参数设置为default
        db.session.delete(self)	 # 删除原分类
        db.session.commit()
  • 删除分类delete_category 视图函数代码:
@admin_bm.route('category/<int:category_id>/delete', methods=['POST'])
@login_required
def delete_category(category_id):
    category = Category.query.get_or_404(category_id)
    if category.id == 1:
        flash('不能删除默认分类!', 'warning')
        return redirect(url_for('blog.index'))
    # 特殊的删除分类方法,在Category类中定义
    category.delete()
    flash('删除分类成功!', 'success')
    return redirect(url_for('.manage_category'))

到此为止我们的博客已经编写完毕,下一节将简单介绍如何将博客部署到pythonanywhere。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值