Flask教程-Flask模板优化
下面是几个非常实用的模板编写技巧,为实现创建和编辑电影条目打下基础。
自定义错误页面: 在Flask程序中自定义错误页面非常简单。首先,我们可以编写一个404错误页面模板,例如templates/404.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ user.name }}'s Watchlist</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css">
</head>
<body>
<h2>
<img alt="Avatar" class="avatar" src="{{ url_for('static', filename='images/avatar.png') }}">
{{ user.name }}'s Watchlist
</h2>
<ul class="movie-list">
<li>
Page Not Found - 404
<span class="float-right">
<a href="{{ url_for('index') }}">Go Back</a>
</span>
</li>
</ul>
<footer>
<small>© 2018 <a href="http://helloflask.com/book/3">HelloFlask</a></small>
</footer>
</body>
</html>
接下来,使用app.errorhandler()
装饰器注册一个错误处理函数,该函数会在发生404错误时被触发,并将其返回值作为响应主体返回给客户端。在这个函数中,我们可以查询数据库并将user
变量传递给模板:
@app.errorhandler(404)
def page_not_found(e):
user = User.query.first()
return render_template('404.html', user=user), 404
这样,当访问一个不存在的URL时,将显示我们自定义的404错误页面。
模板继承: 错误页面模板和主页模板存在大量重复的代码,例如<head>
标签的内容、页首的标题、页脚信息等。为了避免重复的劳动和修改的麻烦,我们可以使用模板继承的概念。
首先,我们创建一个基础模板,例如templates/base.html
,其中包含通用的HTML结构和代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}{% endblock %}</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css">
</head>
<body>
<h2>
<img alt="Avatar" class="avatar" src="{{ url_for('static', filename='images/avatar.png') }}">
{{ user.name }}'s Watchlist
</h2>
{% block content %}{% endblock %}
<footer>
<small>© 2018 <a href="http://helloflask.com/book/3">HelloFlask</a></small>
</footer>
</body>
</html>
然后,在错误页面模板和其他页面模板中,我们可以使用extends
关键字继承基础模板,并使用block
关键字定义可替换的块:
404错误页面模板templates/404.html
:
{% extends 'base.html' %}
{% block title %}{{ user.name }}'s Watchlist{% endblock %}
{% block content %}
<ul class="movie-list">
<li>
Page Not Found - 404
<span class="float-right">
<a href="{{ url_for('index') }}">Go Back</a>
</span>
</li>
</ul>
{% endblock %}
主页模板templates/index.html
:
{% extends 'base.html' %}
{% block title %}{{ user.name }}'s Watchlist{% endblock %}
{% block content %}
<!-- 主页内容 -->
{% endblock %}
使用模板继承可以大大简化模板的编写和维护,通过定义不同的块,我们可以在每个页面中插入特定的内容。
模板中的静态文件: 当在模板中引用静态文件(如CSS样式表、图像等)时,可以使用url_for
函数生成正确的URL。例如,我们在上述示例中使用了url_for
来引用favicon图标、样式表和图像。
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css">
<img alt="Avatar" class="avatar" src="{{ url_for('static', filename='images/avatar.png') }}">
url_for('static', filename='...')
会生成指向静态文件的URL,其中static
是Flask应用程序中静态文件所在的目录。
模板上下文处理函数和模板继承
这是一个非常实用的技巧,可以在多个模板中使用相同的变量而不必重复定义。下面是一个模板上下文处理函数和模板继承的示例代码,帮助你更好地理解:
# 注册模板上下文处理函数
@app.context_processor
def inject_user():
user = User.query.first()
return dict(user=user)
在这个示例中,我们定义了一个名为inject_user
的模板上下文处理函数。它会查询数据库并将第一个用户对象赋给user
变量。然后,我们通过return
语句返回一个字典,将user
作为键,其值为user
变量。这样,user
变量就可以在所有模板中使用。
接下来,我们使用模板继承的机制来组织模板结构。我们创建了一个基础模板base.html
,其中包含了通用的HTML结构、导航栏、页脚等部分。基础模板中定义了两个块(block
),分别是head
和content
:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<!-- head内容 -->
{% endblock %}
</head>
<body>
<!-- 导航栏 -->
<nav>
<ul>
<li><a href="{{ url_for('index') }}">Home</a></li>
</ul>
</nav>
{% block content %}
<!-- content内容 -->
{% endblock %}
<footer>
<!-- 页脚内容 -->
</footer>
</body>
</html>
在子模板中,我们使用extends
标签声明继承自基础模板,并通过block
标签定义需要替换或追加内容的块。例如,主页模板index.html
继承自base.html
,并在content
块中定义了主页的内容:
{% extends 'base.html' %}
{% block content %}
<!-- 主页内容 -->
{% endblock %}
404错误页面模板404.html
同样继承自base.html
,并在content
块中定义了404错误页面的内容:
{% extends 'base.html' %}
{% block content %}
<!-- 404错误页面内容 -->
{% endblock %}
使用模板上下文处理函数和模板继承,我们可以在多个模板中使用相同的变量,并将模板的结构组织得更加清晰和可维护。
添加 IMDb 链接
在主页模板中,我们为每个电影条目右侧添加了一个IMDb链接。下面是对应的HTML代码和CSS样式:
<span class="float-right">
<a class="imdb" href="https://www.imdb.com/find?q={{ movie.title }}" target="_blank" title="Find this movie on IMDb">IMDb</a>
</span>
.float-right {
float: right;
}
.imdb {
font-size: 12px;
font-weight: bold;
color: black;
text-decoration: none;
background: #F5C518;
border-radius: 5px;
padding: 3px 5px;
}
在这段代码中,我们使用了一个<span>
元素将IMDb链接包裹起来,并为它添加了float-right
类,使其靠右对齐。链接本身使用<a>
标签表示,其中href
属性设置为IMDb搜索页面的URL,通过查询参数q
传入电影的标题。target="_blank"
属性将链接在新标签页中打开。另外,我们还使用了一些CSS样式来设置链接的字体、颜色、背景色等。