Flask 教程 第十一章:美化

百度云搜索,搜各种资料:http://bdy.lqkweb.com

搜网盘,搜各种资料:http://www.swpan.cn

本文翻译自The Flask Mega-Tutorial Part XI: Facelift

这是Flask Mega-Tutorial系列的第十一部分,我将告诉你如何用基于Bootstrap用户界面框架的新模板替换基础的HTML模板。

你把玩Microblog应用也有一段时间了,所以我相信你已经注意到,我没有花太多时间来美化它,说得更具体点,我根本没有花时间。 所有的模板只使用了基础样式,没有任何自定义的展现。 这对于我来说却非常有用,因为我可以专注于应用的实际逻辑,不用分心于编写好看的HTML和CSS代码。

但是我已经长期关注应用的后端部分一段时间了。 因此在本章中,我暂停一下后端的工作,并花点时间向你展示如何使应用看起来更加优雅和专业。

本章将与之前的章节略有不同,因为我不会像平常解说Python那样,事无巨细,一一道来,毕竟Python才是本教程的主要内容。 创建漂亮的网页是一个很广泛的话题,而与Python Web的后端开发很大程度上无关,因此我将讨论一些基本的指导方针和想法,你可以通过重新设计应用的外观来研究和学习它。

本章的GitHub链接为:Browse, Zip, Diff.

CSS框架

虽然我们可以争辩说写代码不容易,但是与那些必须让网页在所有Web浏览器上具有良好一致外观的网页设计师相比,我们的痛苦不值一提。 虽然近年来这种情况得到一定程度的缓解,但是在一些浏览器中仍然存在着晦涩的错误或奇怪的设定,这使得设计网页的任务变得非常困难。 如果还需要兼容屏幕限制设备(诸如平板电脑和智能手机)的浏览器,则更加困难。

如果你和我一样,只是一个想创建出规范网页的开发人员,没有时间或兴趣去学习底层机制并通过编写原生HTML和CSS来实现它,那么唯一可行的解决方案是使用CSS框架来简化任务。 通过这种方式,你会失去一些创造性的自由,但另一方面,无需通过太多的功夫就可以让网页在所有浏览器中看起来都不错。 CSS框架为普通类型的用户界面元素提供了高级CSS类的集合,其中包含预定义样式。 大多数这样的框架还提供JavaScript插件,以实现不能纯粹使用HTML和CSS来完成的功能。

Bootstrap简介

最受欢迎的CSS框架之一是由Twitter推出的Bootstrap。 如果你想看看这个框架可以设计的页面类型,文档有一些示例

这些是使用Bootstrap来设置网页风格的一些好处:

  • 在所有主流网页浏览器中都有相似的外观
  • 自动处理PC桌面,平板电脑和手机屏幕尺寸
  • 可定制的布局
  • 精心设计的导航栏,表单,按钮,警示,弹出窗口等

使用Bootstrap最直接的方法是简单地在你的基本模板中导入bootstrap.min.css文件。 可以下载此文件并将其添加到你的项目中,或直接从CDN导入。 然后,你可以根据其文档开始使用它提供的通用CSS类,实在是太棒了。 你可能还需要导入包含框架JavaScript代码的bootstrap.min.js文件,以便使用最先进的功能。

幸运的是,有一个名为Flask-Bootstrap的Flask插件,它提供了一个已准备好的基础模板,该模板引入了Bootstrap框架。 让我们来安装这个扩展:

(venv) $ pip install flask-bootstrap

使用Flask-Bootstrap

Flask-Bootstrap需要像大多数其他Flask插件一样被初始化:

app/init.py: Flask-Bootstrap实例。

# ...
from flask_bootstrap import Bootstrap

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

在初始化插件之后,bootstrap/base.html模板就会变为可用状态,你可以使用extends子句从应用模板中引用。

但是,回顾一下,我已经使用了extends子句来继承我的基础模板,这使我可以将页面的公共部分放在一个地方。 base.html模板定义了导航栏,其中包含几个链接,并且还导出了一个content块。 应用中的所有其他模板都从基础模板继承,并为内容块提供页面的主要内容。

那么我怎样才能适配Bootstrap基础模板呢? 解决方案是从使用两个层级到使用三个层级。 bootstrap/base.html模板提供页面的基本结构,其中引入了Bootstrap框架文件。 这个模板为派生的模板定义了一些块,例如titlenavbarcontent(参见块的完整列表)。 我将更改base.html模板以从bootstrap/base.html派生,并提供titlenavbarcontent块的实现。 反过来,base.html将为从其派生的模板导出app_content块以定义页面内容。

下面你可以看到从Bootstrap基础模板派生的base.html的代码。 请注意,此列表不包含导航栏的整个HTML,但你可以在GitHub上或下载本章的代码来查看完整的实现。

app/templates/base.html:重新设计后的基础模板。

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

{% block title %}
    {% if title %}{{ title }} - Microblog{% else %}Welcome to Microblog{% endif %}
{% endblock %}

{% block navbar %}
    <nav class="navbar navbar-default">
        ... navigation bar here (see complete code on GitHub) ...
    </nav>
{% endblock %}

{% block content %}
    <div class="container">
        {% with messages = get_flashed_messages() %}
        {% if messages %}
            {% for message in messages %}
            <div class="alert alert-info" role="alert">{{ message }}</div>
            {% endfor %}
        {% endif %}
        {% endwith %}

        {# application content needs to be provided in the app_content block #}
        {% block app_content %}{% endblock %}
    </div>
{% endblock %}

从中你可以看到我如何从bootstrap/base.html派生此模板,接下来分别实现了页面标题、导航栏和页面内容的这三个模块。

title块需要使用<title>标签来定义用于页面标题的文本。 对于这个块我简单地挪用了原始基本模板中<title>标签内部的逻辑。

navbar块是一个可选块,用于定义导航栏。 对于此块,我调整了Bootstrap导航栏文档中的示例,以便它在左侧展示网站品牌,跟着是Home和Explore的链接。 然后我添加了个人主页和登录或注销链接并使其与页面的右边界对齐。 正如我上面提到的,我在上面的例子中省略了HTML,但是你可以从本章的下载包中获得完整的base.html模板。

最后,在content块中,我定义了一个顶级容器,并在其中设定了呈现闪现消息的逻辑,这些消息现在将显示为Bootstrap警示的样式。 接下来是一个新的app_content块,这个块用于从其派生的模板来定义他们自己的内容。

所有页面模板的原始版本在名为content的块中定义了它们的内容。 正如你在上面看到的,Flask-Bootstrap使用名为content的块,所以我将我的内容块重命名为app_content。 所以我所有的模板都必须重命名为使用app_content作为它们的内容块。 例如,这是404.html模板的修改后版本的展示:

app/templates/404.html:重新设计后的404错误模板。

{% extends "base.html" %}

{% block app_content %}
    <h1>File Not Found</h1>
    <p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}

渲染Bootstrap表单

Flask-Bootstrap在渲染表单这方面做得非常出色。 Flask-Bootstrap不需要逐个设置表单字段,而是使用一个接受Flask-WTF表单对象作为参数的宏,并以Bootstrap样式渲染出完整的表单。

下面你可以看到重新设计后的register.html模板:

app/templates/register.html::用户注册模板。

{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}

{% block app_content %}
    <h1>Register</h1>
    <div class="row">
        <div class="col-md-4">
            {{ wtf.quick_form(form) }}
        </div>
    </div>
{% endblock %}

是不是很棒? 顶端附近的import语句与Python导入类似。 这增加了一个wtf.quick_form()宏,它在单行代码中渲染完整的表单,包括对显示验证错误的支持,并且适配Bootstrap框架的所有样式。

再一次地,我不会向你展示我为应用中的其他表单所做的所有更改,但这些更改都是可以在GitHub上下载或检查到的。

渲染用户动态

单条用户动态的渲染逻辑被提取到名为_post.html的子模板中。 我只需要在这个模板上做一些很小的调整,就可以使其在Bootstrap下看起来很棒了。

app/templates/_post.html: 重新设计后的用户动态子模板。

    <table class="table table-hover">
        <tr>
            <td width="70px">
                <a href="{{ url_for('user', username=post.author.username) }}">
                    <img src="{{ post.author.avatar(70) }}" />
                </a>
            </td>
            <td>
                <a href="{{ url_for('user', username=post.author.username) }}">
                    {{ post.author.username }}
                </a>
                says:
                <br>
                {{ post.body }}
            </td>
        </tr>
    </table>

渲染分页链接

分页链接是Bootstrap提供直接支持的另一个方面。 为此,我再一次访问Bootstrap 文档,并修改了其中的一个示例。 以下是在index.html页面中的分页链接的代码:

app/templates/index.html: 重新设计后的分页链接。

    ...
    <nav aria-label="...">
        <ul class="pager">
            <li class="previous{% if not prev_url %} disabled{% endif %}">
                <a href="{{ prev_url or '#' }}">
                    <span aria-hidden="true">&larr;</span> Newer posts
                </a>
            </li>
            <li class="next{% if not next_url %} disabled{% endif %}">
                <a href="{{ next_url or '#' }}">
                    Older posts <span aria-hidden="true">&rarr;</span>
                </a>
            </li>
        </ul>
    </nav>

请注意,在分页链接的实现中,当某个方向没有更多内容时,不是隐藏该链接,而是使用禁用状态,这会使该链接显示为灰色。

类似的更改需要应用于user.html,但我不打算展示在此处。 本章的下载包中包含这些更改。

对比

请下载本章的zip文件并更新应用。

下面你可以对照几张美化前后的图片来观察转变情况。 请记住,这种转变是在不改变一行应用逻辑代码的情况下实现的!

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

推荐阅读更多精彩内容