[叁]Flask web开发:模板
admin
2023-07-31 01:47:45
0

本系列笔记是我阅读Miguel Grinberg的《Flask Web Development》的笔记,标题与书本同步。希望通过记录技术笔记的方式促进自己对知识的理解。

本篇对应书本第三章:模板。

模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替代变量,再返回最终得到的响应字符串,这一过程成为渲染。

Jinja2模板引擎

Flask渲染模板使用的是Jinja2模板引擎。

渲染模板

hello.py 渲染模板
from flask import Flask,render_template

#...

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

@app.route(\'/user/\')
def user(name):
    return render_template(\'user.html\',name=name)
    
# Flask提供的render_template函数把Jinja2模板引擎集成到了程序中。
# render_template函数的第一个参数是模板的文件名。
# 随后的参数都是键值对,表示模板中变量对应的真实值。

变量

模板中使用的{{ name }}结构表示一个变量,它是一种特殊的占位符,告诉模块引擎这个位置的值从渲染模板时使用的数据中获取。

Jinja2能识别所有类型的变量,示例:

A value from a dictionary:{{ mydict[\'key\']}}.

A value from a list:{{ mylist[3]}}.

A value from a list,with a variable index:{{ mylist[myintvar] }}.

A value from an object\'s method: {{ myobj.somemethod() }}.

变量过滤器

过滤器名添加在变量之后,中间使用竖线分隔。

hello, {{ name|capitalize }}

常用过滤器:

过滤器名 说明
safe 渲染值时不转义
capitalize 把值得首字母转换成大写,其他字母转换成小写
lower 把值转换成小写形式
upper 把值转换成大写形式
title 把值中每个单词的首字母都换成大写
trim 把值的首位空格去掉
striptags 渲染之前把值中所有的HTML标签都删掉

控制结构

条件控制结构

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

渲染一组元素

    {% for comment in comments %}
  • {{ comment }}
  • {% endfor %}

{{% macro render_comment(comment)%}}
    
  • {{ comment }}
  • {{ endmacro }}
      {% for comment in comments %} {{ render_comment(comment) }} {% endfor %}
    为了重复使用宏,保存在单独文件中,再在需要的模板中导入。 {% import \'macro.html\' as macros %}
      {% for comment in comments%} {{ macros.render_comment(comment)}} {% endfor%}

    复用代码片段

    {% include \'common.html\' %}
    

    模板继承

    - 建一个名为base.html的基模板
    
    
        {% block head %}
        {% block title %}{% endblock %} - My Application
        {% endblock %}
    
    
        {% block body %}
        {% endblock %}
    
    
    
    - 衍生模板中修改block标签定义的元素
    {% extends \"base.html\" %} #定义基模板
    {% block title%}Index{% endblock %} #修改title块内容
    {% block head %} #修改head块内容
        {{ super() }} #原来head中有内容,用super()获取原来的内容
        
    {% endblock %}
    {% block body %} #修改body块内容
    

    Hello, World!

    {% endblock %}

    使用Flask-Bootstrap集成Twitter Bootstrap

    Bootstrap是Twitter开发的一个开源框架,它提供用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代Web浏览器。Bootstrap是客户端框架,不会直接涉及服务器。可以在模板中引用Bootstrap的CSS和JavaScript文件。

    安装Flask-Bootstrap扩展

    (venv)$ pip install flask-bootstrap
    
    hello.py: 初始化Flask-Bootstrap
    from falsk_bootstrap import Bootstrap
    # ...
    bootstrap = Bootstrap(app)
    

    使用Flask-Bootstrap的模板

    {% extends \"bootstrap/base.html\" %}
    
    {% block title%}Flasky{% endblock %}
    
    {% block navbar %}
    
    Flasky
    {% endblock %} {% block content %}

    Hello,{{ name }}!

    {% endblock %} # 模板利用Bootstrap中的样式进行了修改

    Flask-Bootstrap基模板中定义的块

    块名 说明
    doc 整个HTML文档
    html_attribs 标签的属性
    html 标签中的内容
    head 标签中的内容
    title 标签中的内容</td> </tr> <tr> <td>metas</td> <td>一组<meta>标签</td> </tr> <tr> <td>styles</td> <td>层叠样式表定义</td> </tr> <tr> <td>body_attribs</td> <td><body>标签的属性</td> </tr> <tr> <td>body</td> <td><body>标签中的内容</td> </tr> <tr> <td>navbar</td> <td>用户定义的导航条</td> </tr> <tr> <td>content</td> <td>用户定义的页面内容</td> </tr> <tr> <td>scripts</td> <td>文档底部的JavaScript声明</td> </tr> </tbody> </table> <h1 id="%e8%87%aa%e5%ae%9a%e4%b9%89%e9%94%99%e8%af%af%e9%a1%b5%e9%9d%a2">自定义错误页面</h1> <blockquote> <p>利用Jinja2的模板继承机制可以让templates/base.html继承自bootstrap/base.html。</p> <pre><code>{% extends \"bootstrap/base.html\" %} {% block title %}Flasky{% endblock %} {% block navbar %} <div class=\"navbar navbar-inverse\" role=\"navigation\"> <div class=\"container\"> <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=\"/\">Flasky</a> </div> <div class=\"navbar-collapse collapse\"> <ul class=\"nav navbar-nav\"> <li><a href=\"/\">Home</a></li> </ul> </div> </div> </div> {% endblock %} {% block content %} <div class=\"container\"> {% block page_content %}{% endblock %} </div> {% endblock %} </code></pre> <p>程序现在使用的模板继承自templates/base.html不是直接继承自Flask-Bootstrap的基模板。</p> </blockquote> <pre><code>404错误页面:继承自templates/base.html {% extends \"base.html\" %} {% block title %}Flasky - Page Not Found{% endblock %} {% block page_content %} <div class=\"page-header\"> <h1>Not Found</h1> </div> {% endblock %} user页面:继承自templates/base.html {% extends \"base.html\" %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class=\"page-header\"> <h1>Hello, {{ name }}!</h1> </div> {% endblock %} </code></pre> <h1 id="%e9%93%be%e6%8e%a5">链接</h1> <blockquote> <p>Flask提供了url_for()辅助函数,它可以使用程序URL映射中保存的信息生成URL。</p> </blockquote> <ul> <li> <p>url_for函数最简单的用法:以视图函数名作为参数,返回对应的URL。url_for(\’index\’)得到的结果是\’/\’</p> </li> <li> <p>使用url_for生成动态地址时,将动态部分作为关键字参数传入。<br />url_for(\’user\’,name=\’john\’,_external=True)</p> </li> <li> <p>函数能将任何额外参数添加到查询字符串中。</p> </li> </ul> <h1 id="%e9%9d%99%e6%80%81%e6%96%87%e4%bb%b6">静态文件</h1> <h2 id="%e4%bd%bf%e7%94%a8flask-moment%e6%9c%ac%e5%9c%b0%e5%8c%96%e6%97%a5%e6%9c%9f%e5%92%8c%e6%97%b6%e9%97%b4">使用Flask-Moment本地化日期和时间</h2> <blockquote> <p>Flask-Moment是Flask的一个程序扩展,能够在浏览器中渲染日期和时间。</p> </blockquote> <p>安装Flask-Moment</p> <pre><code>(venv)$ pip install flask-moment </code></pre> <h2 id="hello-py%e5%88%9d%e5%a7%8b%e5%8c%96flask-moment">hello.py:初始化Flask-Moment</h2> <pre><code>from flask_moment import Moment moment = Moment(app) </code></pre> <h2 id="templates-base-html-%e5%bc%95%e5%85%a5-moment-js%e5%ba%93">templates/base.html: 引入 moment.js库</h2> <pre><code>{% block scripts %} {{ super() }} {{ moment.include_moment() }} {% endblock %} </code></pre> <h2 id="hello-py-%e5%8a%a0%e5%85%a5%e4%b8%80%e4%b8%aadatetime%e5%8f%98%e9%87%8f">hello.py: 加入一个datetime变量</h2> <pre><code>from date.time import datetime @app.route(\'/\') def index(): return render_template(\'index.html\',current_time=datetime.utcnow()) </code></pre> <h2 id="templates-index-html-%e4%bd%bf%e7%94%a8flask-moment%e6%b8%b2%e6%9f%93%e6%97%b6%e9%97%b4%e6%88%b3">templates/index.html: 使用Flask-Moment渲染时间戳</h2> <pre><code><p>The local date and time is {{ moment(current_time).format(\'LLL\') }}.</p> <p>That was {{ moment(current_time).fromNow(refresh=True) }}.</p> </code></pre> <hr /> <p>本文由 <strong>EverFighting</strong> 创作,采用 **[知识共享署名 3.0 中国大陆许可协议]</p> <!--end::Text--> </div> <!--end::Description--> <div class="mt-5"> <!--关键词搜索--> <a href="/index.php?s=article&c=search&keyword=python" class="badge badge-light-primary fw-bold my-2" target="_blank">python</a> <a href="/index.php?s=article&c=search&keyword=flask" class="badge badge-light-primary fw-bold my-2" target="_blank">flask</a> </div> <div class="mt-5"> <p class="fc-show-prev-next"> <strong>上一篇:</strong><a href="/program/39907.html">pyenv 安装配置与国内镜像加速 结合 virtualenv</a><br> </p> <p class="fc-show-prev-next"> <strong>下一篇:</strong><a href="/program/39909.html">SICP Python描述 1.1 引言</a> </p> </div> <!--begin::Block--> <div class="d-flex flex-stack mb-2 mt-10"> <!--begin::Title--> <h3 class="text-dark fs-5 fw-bold text-gray-800">相关内容</h3> <!--end::Title--> </div> <div class="separator separator-dashed mb-9"></div> <!--end::Block--> <div class="row g-10"> </div> </div> <!--end::Table widget 14--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-xl-4 mt-0"> <!--begin::Chart Widget 35--> <div class="card card-flush h-md-100"> <!--begin::Header--> <div class="card-header pt-5 "> <!--begin::Title--> <h3 class="card-title align-items-start flex-column"> <!--begin::Statistics--> <div class="d-flex align-items-center mb-2"> <!--begin::Currency--> <span class="fs-5 fw-bold text-gray-800 ">热门资讯</span> <!--end::Currency--> </div> <!--end::Statistics--> </h3> <!--end::Title--> </div> <!--end::Header--> <!--begin::Body--> <div class="card-body pt-3"> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/4386.html" class="text-dark fw-bold text-hover-primary fs-6">Mobi、epub格式电子书如...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/831667.html" class="text-dark fw-bold text-hover-primary fs-6">定时清理删除C:\Progra...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/9fc6c8bf38a85fb.png#没有设置高宽参数,将以原图输出')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/831666.html" class="text-dark fw-bold text-hover-primary fs-6">scoped_dir32_70...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/39278.html" class="text-dark fw-bold text-hover-primary fs-6">500 行 Python 代码...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/783.html" class="text-dark fw-bold text-hover-primary fs-6">小程序支付时提示:appid和...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">[Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/831649.html" class="text-dark fw-bold text-hover-primary fs-6"> pycparser 是一个用...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">`pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/4837.html" class="text-dark fw-bold text-hover-primary fs-6">微信小程序使用slider实现...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/3333.html" class="text-dark fw-bold text-hover-primary fs-6">65536是2的几次方 计算2...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/831541.html" class="text-dark fw-bold text-hover-primary fs-6">Apache Doris 2....</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/program/4969.html" class="text-dark fw-bold text-hover-primary fs-6">项目管理和工程管理的区别</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...</span> </div> <!--end::Title--> </div> </div> <!--end::Body--> </div> <!--end::Chart Widget 35--> </div> <!--end::Col--> </div> </div> <!--end::Content container--> </div> <!--end::Content--> </div> <!--end::Content wrapper--> <!--begin::Footer--> <div id="kt_app_footer" class="app-footer"> <!--begin::Footer container--> <div class="app-container container-xxl d-flex flex-column flex-md-row flex-center flex-md-stack py-3"> <!--begin::Copyright--> <div class="text-dark order-2 order-md-1"> <span class="text-muted fw-semibold me-1">2025 ©</span> 晓说杂谈<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?f7b4581e1f9f88ac28d46df58a8d3ff5"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> <a target="_blank" href="https://beian.miit.gov.cn/">豫ICP备13019747号-13</a> </div> <!--end::Copyright--> <!--begin::Menu--> <ul class="menu menu-gray-600 menu-hover-primary fw-semibold order-1"> <li class="menu-item"> <a href="/tech" target="_blank" class="menu-link px-2">科技分享</a> </li> <li class="menu-item"> <a href="/web" target="_blank" class="menu-link px-2">网络技术</a> </li> <li class="menu-item"> <a href="/hardware" target="_blank" class="menu-link px-2">硬件设备</a> </li> <li class="menu-item"> <a href="/program" target="_blank" class="menu-link px-2">程序人生</a> </li> <li class="menu-item"> <a href="/jinrong" target="_blank" class="menu-link px-2">探索发现</a> </li> <li class="menu-item"> <a href="/jixie" target="_blank" class="menu-link px-2">机械加工</a> </li> <li class="menu-item"> <a href="/dianshang" target="_blank" class="menu-link px-2">电商</a> </li> <li class="menu-item"> <a href="/other" target="_blank" class="menu-link px-2">其他</a> </li> <li class="menu-item"> <a href="/zhishi" target="_blank" class="menu-link px-2">日常知识</a> </li> <li class="menu-item"> <a href="/yulu" target="_blank" class="menu-link px-2">每日语录</a> </li> </ul> <!--end::Menu--> </div> <!--end::Footer container--> </div> <!--end::Footer--> </div> <!--end:::Main--> </div> <!--end::Wrapper--> </div> <!--end::Page--> </div> <!--end::App--> <div id="kt_scrolltop" class="scrolltop" data-kt-scrolltop="true"> <!--begin::Svg Icon | path: icons/duotune/arrows/arr066.svg--> <span class="svg-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect opacity="0.5" x="13" y="6" width="13" height="2" rx="1" transform="rotate(90 13 6)" fill="currentColor"></rect> <path d="M12.5657 8.56569L16.75 12.75C17.1642 13.1642 17.8358 13.1642 18.25 12.75C18.6642 12.3358 18.6642 11.6642 18.25 11.25L12.7071 5.70711C12.3166 5.31658 11.6834 5.31658 11.2929 5.70711L5.75 11.25C5.33579 11.6642 5.33579 12.3358 5.75 12.75C6.16421 13.1642 6.83579 13.1642 7.25 12.75L11.4343 8.56569C11.7467 8.25327 12.2533 8.25327 12.5657 8.56569Z" fill="currentColor"></path> </svg> </span> <!--end::Svg Icon--> </div> <!--begin::Javascript--> <script>var hostUrl = "/static/default/pc/";</script> <!--begin::Global Javascript Bundle(mandatory for all pages)--> <script src="/static/default/pc/plugins/global/plugins.bundle.js"></script> <script src="/static/default/pc/js/scripts.bundle.js"></script> <!--end::Global Javascript Bundle--> <!--end::Javascript--> </body> <!--end::Body--> </html>