Day02 Jinja2模板引擎, 使用Twitter Bootstrap

源代码: https://github.com/ltoddy/flask-tutorial

技术交流群:630398887(欢迎一起吹牛)

有些地方没看懂没关系,坚持往下看,下面会有演示代码来说明。

上一篇中如下代码

@app.route('/')
def hello_world():
    return 'Hello World!'

这个样子返回一个字符串,很不爽,能不能直接返回一个HTML页面,当然可以。

在templates文件夹下新建一个index.html

<small>templates/index.html</small>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Just for fun</title>
</head>
<body>

<h1>Hello World</h1>

</body>
</html>

<small>blog.py</small>

from flask import render_template
#...
@app.route('/')
def hello_world():
    return render_template('index.html')

这个样子就直接把那个index.html页面显示了出来.

Jinja2模板引擎

渲染模板

在blog.py的def user(username) 这个函数中,如果我们想把那个username传入html页面怎么办呢?
在templates文件夹下新建user.html

<small>templates/user.html</small>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Just for fun</title>
</head>
<body>

<h1>Hello {{ name }}.</h1>

</body>
</html>

视图函数user()返回的响应中包含一个使用变量表示的动态部分.
<small>blog.py</small>

@app.route('/<username>')
def user(username):
    return render_template('user.html', name=username)

注意看这里的对应关系,在return那里,render_template接受了如下两个部分:

  • 'user.html' 这个是要展现的页面名字,页面要放在templates文件夹下,jinja2引擎会自动去templates文件夹寻找此文件.
  • 第二部分就是user.html中所需要的参数,这里可以有很多个参数,下文将会看到.在这里,name=username,左边的name表示参数名,就是模板中使用的占位符,右边的username是当前作用域中的变量.

变量

刚才使用的{{ name }}结构表示一个变量,它是一个特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取.
Jinja2能识别所有类型的变量,甚至是一些特殊的类型:例如列表,字典和对象.
e.g.

  • <p>A value from a dictionary: {{ mydict['key'] }}.</p>
  • <p>A value from a list: {{ mylist[3] }}.</p>
  • <p>A value from a list, with a variable index: {{ mylist[myintvar] }}</p>
  • <p>A value from a object's method: {{ myobj.somemethod() }}.</p>

Jinja2另外也提供了叫 过滤器 的东西,但是不怎么用,这里就不再说明了。

Jinja2过滤器完整文档

控制结构

条件控制结构语句:

{% if user %}
    Hello, {{ user }}!
{% else %}
    Hello, Stranger!
{% endif %}

循环控制结构

<ul>
    {% for comment in comments %}
        <li>comment</li>
    {% endfor %
</ul>

需要在多出重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复:

{% include 'common.html' %}

另一种重复使用代码的强大方式是模板继承.
首先创建一个名为base.html的模板

<html lang="en">
<head>
    {% block head %}
        <title>{% block title %}{% endblock %} - My Application</title>
    {% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>

block标签定义的元素可在衍生模板中修改.例如

{% extends 'base.html' %}
{% block title %}Index{% endblock %}
{% block head %}
    {{ super() }}
    <style>
    </style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}

block标签定义的元素可以在衍生的模板中修改.
extends指令声明这个模板衍生自base.html.在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置.

使用Flask-Bootstrap集成Twitter Bootstrap

如果电脑上有pip的可以:

pip install flask-bootstrap

没有的就如上篇文章那样,通过Pycharm自动帮你安装.
Bootstrap CSS样式库,简单点理解就是你获得了一大堆化妆品(定制好的,而非按照自己想法定制的样子),可以有选择的去使用.

初始化Flask-Bootstrap:

from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)

待会要通过继承Bootstrap的base.html页面来实现模板的复用.
先看看bootstrap的base.html为我们提供了什么:

{% block doc -%}
    <!DOCTYPE html>
    <html{% block html_attribs %}{% endblock html_attribs %}>
    {%- block html %}
        <head>
            {%- block head %}
                <title>{% block title %}{% endblock title %}</title>

                {%- block metas %}
                    <meta name="viewport" content="width=device-width, initial-scale=1.0">
                {%- endblock metas %}

                {%- block styles %}
                    <!-- Bootstrap -->
                    <link href="{{ bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap') }}" rel="stylesheet">
                {%- endblock styles %}
            {%- endblock head %}
        </head>
        <body{% block body_attribs %}{% endblock body_attribs %}>
        {% block body -%}
            {% block navbar %}
            {%- endblock navbar %}
            {% block content -%}
            {%- endblock content %}

            {% block scripts %}
                <script src="{{ bootstrap_find_resource('jquery.js', cdn='jquery') }}"></script>
                <script src="{{ bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap') }}"></script>
            {%- endblock scripts %}
        {%- endblock body %}
        </body>
    {%- endblock html %}
    </html>
{% endblock doc -%}

主要用到两个块: navbar(导航栏)和content(页面主要内容).

在templates文件夹下新建base.html文件

<small>templates/base.html</small>

{% extends 'bootstrap/base.html' %}

{% block title %}Just for fun{% endblock %}

{% block navbar %}
    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">Just for fun</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="/">Home</a></li>
                </ul>
            </div>
        </div>
    </nav>
{% endblock %}

{% block content %}
    <div class="container">
        {% block page_content %}{% endblock %}
    </div>
{% endblock %}

然后我们更改一下index.html和user.html
<small>templates/index.html</small>

{% extends 'base.html' %}

{% block page_content %}
    <div class="page-header">
        <h1>Hello World!</h1>
    </div>
{% endblock %}

<small>templates/user.html</small>

{% extends 'base.html' %}

{% block page_content %}
    <div class="page-header">
        <h1>Hello {{ name }}.</h1>
    </div>
{% endblock %}

OK,我们运行一下看看效果:



还不错.

自定义错误页面.

有时候输入一个错误的网址的时候,会返回一个404 page not found错误.
分别在templates文件夹下创建404.html和500.html

<small>templates/404.html</small>

{% extends 'base.html' %}

{% block title %}404 - Page Not Found{% endblock %}

{% block page_content %}
    <div class="page-header">
        <h1>Not Found</h1>
    </div>
{% endblock %}

<small>templates/500.html</small>

{% extends 'base.html' %}

{% block title %}500 - Internal Server Error{% endblock %}

{% block page_content %}
    <div class="page-header">
        <h1>Server Error</h1>
    </div>
{% endblock %}

以及我们要在blog.py中添加相应的路由:
<small>blog.py</small>

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

看一下blog.py的完整代码:
<small>blog.py</small>

from flask import Flask
from flask import render_template
from flask_bootstrap import Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)


@app.route('/')
def hello_world():
    return render_template('index.html')


@app.route('/<username>')
def user(username):
    return render_template('user.html', name=username)


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


if __name__ == '__main__':
    app.run(debug=True)

在最后一行,我加入了:debug=True,目的是当你对程序做出了改变之后,不需要手动重启项目,项目会自动帮你做出重启.

最后说一点内容,下一篇将会用到

使用Flask-Script支持命令行选项

安装Flask-Script:

pip install flask-script

Flask的开发web服务器支持很多启动设置选项,传递设置选项的理想方式是使用命令行参数.

e.g.:

from flask_script import Manager
manager = Manager(app)

# ...

if __name__ == '__main__':
    manager.run()

此时的完整代码:
<small>blog.py</small>

from flask import Flask
from flask import render_template
from flask_bootstrap import Bootstrap
from flask_script import Manager

app = Flask(__name__)
bootstrap = Bootstrap(app)
manager = Manager(app)


@app.route('/')
def hello_world():
    return render_template('index.html')


@app.route('/<username>')
def user(username):
    return render_template('user.html', name=username)


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


if __name__ == '__main__':
    manager.run()

现在如何启动程序?

在软件的左下角,选择点击Terminal,
输入:

python3 blog.py runserver

如下:



这里要注意一下,我目前使用的是我的Linux系统,Python2和Python3都有,所以这里写明是Python3,如果你电脑上只有Python3,那么你把这里的python3替换成python就可以了.按照自己电脑为主.

然后打开浏览器,在地址栏填入: http://localhost:5000/ 回车就可以了.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容