本系列笔记是我阅读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> </div> </div> <div class="widget widget_tag_cloud mt-5"> <div class="tagcloud"> Tags: <a href="https://www.wxx86.cn/index.php?s=article&c=search&keyword=python" class="tag-cloud-link tag-link-5 tag-link-position-1">python</a> <a href="https://www.wxx86.cn/index.php?s=article&c=search&keyword=flask" class="tag-cloud-link tag-link-5 tag-link-position-1">flask</a> </div> </div> <div class="font-theme text-lg text-muted text-height-xs text-center"> - THE END - </div> <div class="post-lastedit text-xs text-muted bg-light rounded p-3 p-md-3 mt-4"> <div class="d-flex flex-fill align-items-center"> <i class="h1 text-secondary iconfont icon-Warning--circle mr-2"></i> <div class="flex-fill"> <div class="my-1"> 本文由 @<a href="https://www.wxx86.cn/" rel="author">晓说杂谈</a> 修订发布于 2023-07-31 </div> <div class="my-1">本文来自投稿,不代表本站立场,如若转载,请注明出处:https://www.wxx86.cn/program/39908.html</div> </div> </div> </div> <!-- <div class="paid-share mt-5 d-none d-lg-block"> <i class="gg-icon"></i> <img class="lazy loaded" src="image/inad.jpg"> </div> <div class="paid-share mt-4 d-lg-none"> <i class="gg-icon"></i> <img class="lazy loaded" src="image/inad.jpg"> </div> --> <div class="border-top border-bottom border-light py-3 py-md-4 mt-4 mt-md-5"> <div class="row"> <div class="col"> <div class="text-left"> <div class="text-muted mb-md-1"> <a href="https://www.wxx86.cn/program/39907.html" class="font-theme text-xl">PREV</a> </div> <a href="https://www.wxx86.cn/program/39907.html" class="d-none d-md-block text-sm"> <div class="h-1x">pyenv 安装配置与国内镜像加速 结合 virtualenv</div> </a> </div> </div> <div class="col"> <div class="text-right"> <div class="text-muted mb-md-1"> <a href="https://www.wxx86.cn/program/39909.html" class="font-theme text-xl">NEXT</a> </div> <a href="https://www.wxx86.cn/program/39909.html" class="d-none d-md-block text-sm"> <div class="h-1x">SICP Python描述 1.1 引言</div> </a> </div> </div> </div> </div> <div class="post-related mt-5 mt-md-5 "> <div class="row"> <div class="col-lg-12 col-xl-12 pr-lg-5"> <!--内容--> <div class="h5 mt-md-0 mb-3 mb-lg-4"><span>相关文章</span></div> <div class="list list-dots mb-5"> <ul class="row"> </ul> </div> </div> </div> </div> </div> <div class="col-lg-3 col-xl-3 sidebar-right border-left border-light d-none d-xl-block pl-lg-5"> <div id="yk_news_info_hot_read"> <div id="recommended_posts-2" class="widget mb-5 Recommended_Posts"> <div class="h5 mt-md-0 mb-3 mb-lg-4"><span class="pane-header">热门阅读</span></div> <div class="list"> </div> </div> </div> <div id="yk_news_info_hot_comment"> <div class="d-lg-block widget mb-5 Recommended_Posts"> <div class="h5 mt-md-0 mb-3 mb-lg-4"> <span class="pane-header">热评聚合</span> </div> <div class="widget-body"> <div class="list list-hots"> </div> </div> </div> </div> <div id="divTags"> <div class="widget widget_tag_cloud mb-5"> <div class="h5 mt-md-0 mb-3 mb-lg-4"> <span class="pane-header">标签列表</span> </div> <ul class="tagcloud"> <li> <a title="MIUI15" href="/tag/miui15.html" class="tag-cloud-link tag-link-5 tag-link-position-1">MIUI15</a> <a title="小米14" href="/tag/xiaomi14.html" class="tag-cloud-link tag-link-5 tag-link-position-1">小米14</a> <a title="AI大模型" href="/tag/aidamoxing.html" class="tag-cloud-link tag-link-5 tag-link-position-1">AI大模型</a> <a title="郑州地铁10号线" href="/tag/zhengzhouditie10haoxian.html" class="tag-cloud-link tag-link-5 tag-link-position-1">郑州地铁10号线</a> <a title="地铁" href="/tag/ditie.html" class="tag-cloud-link tag-link-5 tag-link-position-1">地铁</a> <a title="死臀综合征" href="/tag/situnzonghezheng.html" class="tag-cloud-link tag-link-5 tag-link-position-1">死臀综合征</a> <a title="thinkphp" href="/tag/thinkphp.html" class="tag-cloud-link tag-link-5 tag-link-position-1">thinkphp</a> <a title="印度" href="/tag/yindu.html" class="tag-cloud-link tag-link-5 tag-link-position-1">印度</a> <a title="facebook" href="/tag/facebook.html" class="tag-cloud-link tag-link-5 tag-link-position-1">facebook</a> <a title="youtube" href="/tag/youtube.html" class="tag-cloud-link tag-link-5 tag-link-position-1">youtube</a> </li> </ul> </div> </div> </div> </div> </div> </main> <footer id="footer"> <div class="container"> <span class="fr"> <img class="footer_beian" src="https://www.wxx86.cn/static/blog6/image/icp.png" alt="icp" width="13"><a href="https://beian.miit.gov.cn/#/Integrated/index" rel="nofollow" target="_blank"></a> </span> <span class="fl"> </span> </div> </footer> <div class="mobile-sidebar"> <div class="mobile-overlay"></div> <div class="mobile-menu"> <ul> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/" title="首页">首页</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/tech" title="科技分享">科技分享</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/web" title="网络技术">网络技术</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/hardware" title="硬件设备">硬件设备</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/program" title="程序人生">程序人生</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/jinrong" title="探索发现">探索发现</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/jixie" title="机械加工">机械加工</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/dianshang" title="电商">电商</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/other" title="其他">其他</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/zhishi" title="日常知识">日常知识</a></li> <li class="navbar-item menu-item "><a href="https://www.wxx86.cn/yulu" title="每日语录">每日语录</a></li> </ul> </div> </div> <div id="widget-to-top"> <ul> <li class="my-2"><a class="btn btn-light btn-icon btn-totop" href="javascript:"><span><i class="text-md iconfont icon-Control"></i></span></a></li> </ul> </div> <template id="site-search-template"> <div class="w-64 mx-auto my-4"> <svg t="1571940901442" class="icon" viewbox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1220" data-spm-anchor-id="a313x.7781069.0.i9" width="64" height="64"> <path d="M345.6 445.525333h-68.266667a12.8 12.8 0 0 1 0-25.6h68.266667a12.8 12.8 0 0 1 0 25.6zM465.066667 321.792h-68.266667a12.8 12.8 0 0 1 0-25.6h68.266667a12.8 12.8 0 0 1 0 25.6z m-119.466667 0h-68.266667a12.8 12.8 0 0 1 0-25.6h68.266667a12.8 12.8 0 0 1 0 25.6z" fill="#1089FF" p-id="1221" data-spm-anchor-id="a313x.7781069.0.i10"></path> <path d="M339.2 806.741333h-145.066667a68.266667 68.266667 0 0 1-68.266666-68.266666v-546.133334a68.266667 68.266667 0 0 1 68.266666-68.266666h576a68.266667 68.266667 0 0 1 68.266667 68.266666v161.450667a68.266667 68.266667 0 0 1-68.266667-68.266667V192.341333h-576v546.133334h76.8a68.266667 68.266667 0 0 1 68.266667 68.266666z" fill="#23374d" p-id="1222" data-spm-anchor-id="a313x.7781069.0.i11" class="selected"></path> <path d="M864 899.925333a34.133333 34.133333 0 0 1-24.149333-9.984L750.933333 801.365333a34.133333 34.133333 0 0 1 48.298667-48.298666l88.576 88.576a34.133333 34.133333 0 0 1-24.149333 58.282666z" fill="#23374d" p-id="1223" data-spm-anchor-id="a313x.7781069.0.i7" class="selected"></path> <path d="M626.602667 872.874667A244.565333 244.565333 0 1 1 799.573333 455.424a244.48 244.48 0 0 1-172.970666 417.450667z m0-420.778667A176.298667 176.298667 0 1 0 750.933333 503.466667a175.872 175.872 0 0 0-124.330666-51.2z" fill="#1089FF" p-id="1224" data-spm-anchor-id="a313x.7781069.0.i8"></path> </svg> </div> <form class="text-center px-md-5 pb-md-5" action="/index.php" method="get"> <input type="hidden" name="s" value="api"> <input type="hidden" name="c" value="api"> <input type="hidden" name="m" value="search"> <input type="hidden" name="dir" value="news" > <div class="form-group mb-md-4"> <input type="text" class="form-control form-control-lg" name="keyword" placeholder="请输入搜索关键词并按回车键…"> </div> <button type="submit" class="btn btn-primary btn-block">搜索</button> </form> </template> <script src="https://www.wxx86.cn/static/blog6/js/theme.js"></script> <script src="https://www.wxx86.cn/static/blog6/js/customer.js"></script> <!--边栏--> <div class="xsidebar-collapse"> <div class="xsidebar-right p-4 p-md-5"> <div class="text-the"> <a href="javascript:" class="action-close mb-4"> <span class="svg-white-close"></span></a> </div> <div class="text-end"> <input class="mui-switch mui-switch-anim" type="checkbox" onclick="javascript:switchNightMode()"> </div> <div class="widget widget_ajax_search mb-5"> <div class="h6 mb-2 mb-md-3"> <span class="text-bottom-line">搜索</span></div> <div class="widget-content"> <div class="search-input"> <form class="search-form" action="/index.php" method="get"> <input type="hidden" name="s" value="api"> <input type="hidden" name="c" value="api"> <input type="hidden" name="m" value="search"> <input type="hidden" name="dir" value="news" > <input type="text" placeholder="请输入搜索关键词" class="form-control" name="keyword" required=""> </form> </div> </div> </div> <div id="recent-posts-2" class="widget widget_recent_entries mb-5"> <div class="h6 mb-2 mb-md-3"><span class="text-bottom-line">最新推荐</span></div> <ul class="list-dots"> </ul> </div> <div id="tag_cloud-3" class="widget widget_tag_cloud mb-5"> <div class="h6 mb-2 mb-md-3"><span class="text-bottom-line">推荐标签</span></div> <div class="tagcloud"> <a title="MIUI15" href="/tag/miui15.html" class="tag-cloud-link tag-link-5 tag-link-position-1">MIUI15</a> <a title="小米14" href="/tag/xiaomi14.html" class="tag-cloud-link tag-link-5 tag-link-position-1">小米14</a> <a title="AI大模型" href="/tag/aidamoxing.html" class="tag-cloud-link tag-link-5 tag-link-position-1">AI大模型</a> <a title="郑州地铁10号线" href="/tag/zhengzhouditie10haoxian.html" class="tag-cloud-link tag-link-5 tag-link-position-1">郑州地铁10号线</a> <a title="地铁" href="/tag/ditie.html" class="tag-cloud-link tag-link-5 tag-link-position-1">地铁</a> <a title="死臀综合征" href="/tag/situnzonghezheng.html" class="tag-cloud-link tag-link-5 tag-link-position-1">死臀综合征</a> <a title="thinkphp" href="/tag/thinkphp.html" class="tag-cloud-link tag-link-5 tag-link-position-1">thinkphp</a> <a title="印度" href="/tag/yindu.html" class="tag-cloud-link tag-link-5 tag-link-position-1">印度</a> <a title="facebook" href="/tag/facebook.html" class="tag-cloud-link tag-link-5 tag-link-position-1">facebook</a> <a title="youtube" href="/tag/youtube.html" class="tag-cloud-link tag-link-5 tag-link-position-1">youtube</a> </div> </div> </div> </div> </body> </html>