我们已经写好验证的 views,但是如果现在启动服务的话
无论开启哪个 URL,都会看到一个TemplateNotFound
错误
这是因为 view 使用了render_template()
,但是 template 档案还没有写
模板档案会存放在 flaskr 资料夹内的templates
文件夹内
Flask 使用Jinja模板引擎来渲染模板,范例中会使用模板来显示在使用者浏览器中的 HTML
在 Flask 中, Jinja 被设定为自动转译 HTML 模板中的任何资料,这代表直接渲染内容是安全的
任何使用者输入的可能被浏览器执行的内容,如<
和>
,会被转译成安全的值
转译的结果在浏览器中看起来一样,但是不会被浏览器执行
Jinja 看上去以及执行起来很像 Python
在 Jinja 中,任何位於{{
和}}
之间的变数会被输出成文字
程序判断式则是放在{%
和%}
之间,例如if
和for
与 Python 不同,不是使用缩排分隔,而是使用特殊 tag 分隔
因为区块内的渲染出来的结果可能有自己的缩排
与其在不同的页面中重写整个页面的 HTML,应该让每一页的模板继承一个基本的共用模板
接着在不同页面中复写需要修改的部分
flaskr/templates/base.html
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
<h1>Flaskr</h1>
<ul>
{% if g.user %}
<li><span>{{ g.user['username'] }}</span>
<li><a href="{{ url_for('auth.logout') }}">Log Out</a>
{% else %}
<li><a href="{{ url_for('auth.register') }}">Register</a>
<li><a href="{{ url_for('auth.login') }}">Log In</a>
{% endif %}
</ul>
</nav>
<section class="content">
<header>
{% block header %}{% endblock %}
</header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</section>
g 在模板中自动可用!
根据g.user
是否被设定(记得吗?之前在load_logged_in_user
中进行)
选择要显示使用者名称和登出按钮,还是注册和登入按钮?
而用於生成 view 网址的url_for()
也是自动可用的,不需要手动指定
在页面标题下面,content 内容的前面,模板会循环显示 get_flashed_messages() 回传的每个消息
可以用这个方式把之前在 view 中使用 flash() 保存的错误讯息显示出来
There are three blocks defined here that will be overridden in the other templates:
模板中定义了三个 block,这些区块内容会被其他模板复写
{% block title %}
会改变当前浏览器分页的 title
{% block header %}
改变页面的标题
{% block content %}
每个页面的具体内容,例如登入表单或者部落格文章
其他模板直接放在templates
资料夹内
为了更好地管理档案,属於某个 blueprints 的模板会被放在与同名的资料夹内
flaskr/templates/auth/register.html
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="username">Username</label>
<input name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Register">
</form>
{% endblock %}
开头使用{% extends 'base.html' %}
对 Jinja 宣告这个模板继承 base.html
并且需要载入相应的 block,所有复写的内容必须位於{% block %}
标签中
一个好用的模式是把{% block title %}
放在{% block header %}
内部
这样不但可以设定 title block,还可以把其值作为 header block 的内容,一举两得!
input
tag 使用了required
属性,告诉浏览器这些输入框是必填的
如果使用者使用不支援持这个属性的旧版浏览器,或者不是用浏览器发出的请求
那麽你还是要在 view 中验证输入资料
即使前端已经做了一些验证,後端还是要完全检查,这一点非常重要!
这个模板除了标题和送出按钮外,和注册模板相同
flaskr/templates/auth/login.html
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Log In{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="username">Username</label>
<input name="username" id="username" required>
<label for="password">Password</label>
<input type="password" name="password" id="password" required>
<input type="submit" value="Log In">
</form>
{% endblock %}
现在验证模板已写好,可以来测试了
启动测试环境之後开启http://127.0.0.1:5000/auth/register
页面
在不填写表单的情况,尝试点击「Register」按钮,浏览器会显示出错信息
尝试在register.html
中删除required
属性後再次点击「Register」按钮
浏览器不会显示错误,而页面会重新载入并显示来自於 view 中 flash() 错误讯息
填写使用者名称和密码後会重定导向到登录页面
尝试输入错误的使用者名称,或者输入正确的使用者名称和错误的密码
真实情况下不要这麽做!会引发资安疑虑,弱点扫描不会过
因为提示骇客错误是来自哪个栏位,接着就可以使用枚举法暴力破解
如果登录成功,那麽会看到一个错误讯息
因为我们还没有写登入後要转向的 view:index
>>: Spring Framework X Kotlin Day 23 Integration Test
前言 我们已经知道了可以用一个 Auto Encoder-Decoder 的结构来学习记忆 Inpu...
结语: 嗨大家,这30天的铁人赛就在今天要画上结尾了。今天就来跟各位聊聊这30天挑战的一些想法跟可以...
=x= 🌵 网页操作权限分流处理及 Yacht Manager - Master Page 後台主版...
写一个自己都喜欢的 side project,是这次铁人赛系列文章的宗旨。 为什麽要写一个自己都喜欢...
假设,你今天写了一个页面或是储存了一些简单的状态或资讯,call了另外一个API或是跳转到不同页面并...