您好,我是码农飞哥,感谢您阅读本文!上一篇文章我们介绍了一分钟快速实现Flask框架的蓝图和视图,这一篇文章我们将接着介绍博客的发布以及编辑。同样是运用视图和蓝图。
- 关于session的设置
- 用户登录
- 在其他视图中验证
- 博客蓝图设置
- 首页
- 发布文章
- 文章修改接口
- 运行效果图
- 登录前
- 登录后
- 总结
关于session的设置
首先需要引入Flask-Session的库。
代码语言:javascript复制Flask-Session==0.3.2
这里是将Session保存到本地。所以,我们需要实例化app时,设置session,代码地址在:flaskr/__init__.py
。
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
@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
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
def create_app():
.....省略其余代码
from flaskr.views import blog
app.register_blueprint(blog.bp)
return app
首页
flaskr/views/blog.py
,这里指定博客的首页为经常访问的页面,所以地址指定/
。
@bp.route('/')
def index():
posts = blog_service.get_last_blog()
return render_template('blog/index.html', posts=posts)
这里将博客的相关Html文件放在一个单独的目录blog下。blog/index.html
<!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
<!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
<!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>
运行效果图
登录前
在这里插入图片描述
登录后
在这里插入图片描述
总结
本文详细介绍了,博客系统的首页代码实现,代码相对比较简单。