Flask框架之博客的发布和编辑

2021-08-18 11:16:55 浏览数 (1)

您好,我是码农飞哥,感谢您阅读本文!上一篇文章我们介绍了一分钟快速实现Flask框架的蓝图和视图,这一篇文章我们将接着介绍博客的发布以及编辑。同样是运用视图和蓝图。

  • 关于session的设置
  • 用户登录
  • 在其他视图中验证
  • 博客蓝图设置
    • 首页
  • 发布文章
    • 文章修改接口
  • 运行效果图
    • 登录前
    • 登录后
  • 总结

关于session的设置

首先需要引入Flask-Session的库。

代码语言:javascript复制
Flask-Session==0.3.2

这里是将Session保存到本地。所以,我们需要实例化app时,设置session,代码地址在:flaskr/__init__.py

代码语言:javascript复制
from flask_session import Session
  #  设置Session
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SECRET_KEY'] = os.urandom(24)
Session(app)

当我们向Session中设置数据时,Flask框架会在项目目录下创建如下文件 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdSlb0va-1610945986545)(./images/1610935419384.png)]。

用户登录

用户登录之后,在登录接口将用户ID放入session中。代码地址是:flaskr/views/auth.py,设置的代码如下:

代码语言:javascript复制
  # 清除session
 session.clear()
 session['user_id'] = user.get_id()

现在用户ID被设置到了sesssion中,可以被后续的请求使用。在每个请求的开头,如果用户已登录,那么其用户信息应当被载入,以使其可用于其他视图。代码地址是:flaskr/views/auth.py

代码语言:javascript复制
@bp.before_app_request
def load_logged_in_user():
    user_id = session.get('user_id')
    if user_id is None:
        g.user = None
    else:
        g.user = user_service.query_user_by_id(user_id)

bp.before_app_request() 注册一个在视图函数之前运行的函数,无论其URL是什么,load_logged_in_user检查用户id是否已经储存在session中,并从数据库中获取用户数据,然后储存在g.user中。g.user的持续时间比请求时间要长,如果没有用户id,或者id不存在,那么g.user将会是None。

在其他视图中验证

装饰器返回一个新的视图,该视图包含了传递给装饰器的原视图,新的函数会检查用户是否已经载入,如果已载入,那么就继续正常执行原视图,否则就重定向到登录页面。

代码语言:javascript复制
def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            return redirect(url_for('auth.login'))
        return view(**kwargs)
    return wrapped_view

博客蓝图设置

前面我们已经设置好了用户的session信息,接下来就是在博客首页中使用了,博客内容的模块,我们新增了一个蓝图。这里我们创建了blog.py文件,这里的blog蓝图没有指定url_prefix。地址是:flaskr/views/blog.py

代码语言:javascript复制
from flask import (
    Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
from flaskr.views.auth import login_required
from flaskr.biz import blog_service

bp = Blueprint('blog', __name__)

接着将该蓝图注册到app中。flaskr/_init_.py

代码语言:javascript复制
def create_app():
 .....省略其余代码
 from flaskr.views import blog
    app.register_blueprint(blog.bp)
 return app

首页

flaskr/views/blog.py,这里指定博客的首页为经常访问的页面,所以地址指定/

代码语言:javascript复制
@bp.route('/')
def index():
    posts = blog_service.get_last_blog()
    return render_template('blog/index.html', posts=posts)

这里将博客的相关Html文件放在一个单独的目录blog下。blog/index.html

代码语言:javascript复制
<!DOCTYPE html>
{% extends 'base.html' %}

{% block header %}
<h1>{% block title %}Posts{% endblock %}</h1>
{% if g.user %}
<a class="action" href="{{ url_for('blog.create') }}">New</a>
{% endif %}
{% endblock %}

{% block content %}
{% for post in posts %}
<article class="post">
    <header>
        <div>
            <h1>{{post['title']}}</h1>
            <div class="about"> by {{ post['username'] }} on{{ post['created'].strftime('%Y-%m-%d') }}</div>
        </div>
        {% if g.user['id']==post['author_id'] %}
        <a class="action" href="{{ url_for('blog.update',id=post['id']) }}">编辑博客</a>
        {% endif %}
    </header>
    <p class="body">{{ post['body'] }}</p>
</article>
{% if not loop.last %}
<hr>
{% endif %}
{% endfor %}
{% endblock %}
</html>

发布文章

代码语言:javascript复制
@bp.route('/create', methods=('GET', 'POST'))
@login_required
def create():
    if request.method == 'POST':
        title = request.form['title']
        body = request.form['body']
        error = None

        if not title:
            error = 'Title is required'
        if error is not None:
            flash(error)
        else:
            blog_service.insert_post(title, body, g.user.get_id())
            return redirect(url_for('blog.index'))
    return render_template('blog/create.html')

发布文章传入title以及body。首先会校验这两参数是否为空,如果都不为空的话,则将文章数据保存到blog表中。对应的页面是blog/create.html

代码语言:javascript复制
 <!DOCTYPE html>
 {% extends 'base.html' %}
 {% block header %}
 <hl>{% block title %}发布文章{% endblock %}</hl>
 {% endblock %}
 {% block content %}
 <form method="post">
  <label for="title">文章标题</label>
  <input name="title" id="title" value="{{ request.form['title'] }}" required>
  <label for="body">文章体</label>
  <textarea name="body" id="body">{{ request.form['body'] }}</textarea>
  <input type="submit" value="Save">
 </form>
 {% endblock %}
 </html>

文章修改接口

文章修改接口,首先是根据id查询文章,如果文章不为空则进行修改。

代码语言:javascript复制
@bp.route('/<int:id>/update', methods=('GET', 'POST'))
@login_required
def update(id):
    post = get_post(id)
    if request.method == 'POST':
        title = request.form['title']
        body = request.form['body']
        error = None

        if not title:
            error = 'Title is required'
        if error is not None:
            flash(error)
        else:
            blog_service.update_post(title, body, id)
            return redirect(url_for('blog.index'))
    return render_template('blog/update.html', post=post)

对应的页面是blog/update.html

代码语言:javascript复制
<!DOCTYPE html>
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}编辑 "{{ post['title'] }}"{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
    <label for="title">标题</label>
    <input name="title" id="title" value="{{ request.form['title'] or post['title'] }}" required>
    <label for="body">文章体</label>
    <textarea name="body" id="body">{{ request.form['body'] or post['body'] }}</textarea>
    <input type="submit" value="保存">
</form>
<form action="{{ url_for('blog.delete',id=post['id']) }}" method="post">
    <input class="danger" type="submit" value="Delete" onclick="return confirm('Are you sure?');">
</form>
{% endblock %}
</html>

运行效果图

登录前

在这里插入图片描述

登录后

在这里插入图片描述

总结

本文详细介绍了,博客系统的首页代码实现,代码相对比较简单。

0 人点赞