Flask默认使用Jinja2作为模版引擎。模版引擎包含了变量和表达式,当模版被渲染时,它们被替换为值和标签,它们控制着模版的逻辑。下面主要回顾模版的渲染使用,以及Jinja2的语法。

1 模版渲染

1.1 目录结构

Flask 会在 templates 文件夹里寻找模板。所以,如果你的应用是个模块,这个文件夹应该与模块同级;如果它是一个包,那么这个文件夹作为包的子目录:
场景1: 模块
application文件应该与templates目录同级

/application.py
/templates/hello.html

场景2: 包
templates目录作为application的子目录

/application/__init__.py/templates/hello.html

1.2 渲染

Flask使用 render_template() 方法来渲染模板。渲染时框架会自动寻找templates目录下的网页文件,不必添加"templates"这个路径。
render_template()方法第一个参数为html文件名,后续参数为模版文件中的变量名,可支持字典类型变量。
在模板里,也可以访问 request 、 session 和 g 对象, 以及 get_flashed_messages() 函数。

用法示例
文件目录结构:

html文件user.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Flask首页</title>
</head>
<body>{% if name %}<h1>Hello {{ name }}!</h1>
{% else %}<h1>Hello world!</h1>
{% endif %}
</body>
</html>

模版渲染代码manager.py:

from flask import Flask, render_template
app = Flask(__name__)@app.route("/user/")
@app.route("/user/<name>")
def index(name=None):return render_template("user.html", name=name)if __name__ == '__main__':app.run(debug=True)

在浏览器中输入URL:http://127.0.0.1:5000/user/bruce
页面显示如下

1.3 字典类型变量

当模版中变量比较多时,可以直接使用字典类型变量。
修改user.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Flask首页</title>
</head>
<body>{% if name %}<h1>Hello {{ name }}!</h1><h2>user age: {{age}}, phone: {{phone}}!</h2>
{% else %}<h1>Hello world!</h1>
{% endif %}
</body>
</html>

修改渲染代码:

from flask import Flask, render_template
app = Flask(__name__)@app.route("/user/")
@app.route("/user/<name>")
def index(name=None):info = {"name": name,"age": 33,"phone": 123456789}return render_template("user.html", **info)if __name__ == '__main__':app.run(debug=True)

浏览器输入URL:http://127.0.0.1:5000/user/bruce.xu

2 Flask变量传递

Jinja 2 默认配置如下:
所有扩展名为 .html 、 .htm 、 .xml 以及 .xhtml 的模板会开启自动转义
模板可以利用 {% autoescape %} 标签选择自动转义的开关。
Flask 在 Jinja2 上下文中插入了几个全局函数和助手,另外还有一些目前默认的值。

Flask全局变量
下面的全局变量默认在 Jinja2 模板中可用

变量 说明
config 当前的配置对象 (flask.config)
request 当前的请求对象 (flask.request)。当模版不是在活动的请求上下文中渲染时这个变量不可用。
session 当前的会话对象 (flask.session)。当模版不是在活动的请求上下文中渲染时这个变量不可用。
g 请求相关的全局变量 (flask.g)。当模版不是在活动的请求上下文中渲染时这个变量不可用。
url_for() flask.url_for() 函数
get_flashed_messages() flask.get_flashed_messages() 函数

(1)请求对象request
request对象可以用来获取请求的方法”request.method”,表单”request.form”,请求的参数”request.args”,请求地址”request.url”等。它本身是一个字典。在模板中,你一样可以获取这些内容,只要用表达式符号”{{ }}”括起来即可。

<p>{{request.url}}</p>

(2)会话对象session
session对象可以用来获取当前会话中保存的状态,它本身是一个字典。在模板中,你可以用表达式符号”{{ }}”来获取这个对象。
在request对象中设置session变量

@app.route('/')
def index():session['user']='guest'returnrender_template('hello.html')app.secret_key='123456'

然后在html中可以使用session变量

<p>User:{{session.user}}</p>

(3)全局对象g
全局变量g,用来保存请求中会用到全局内容,比如数据库连接。模板中也可以访问。
g对象是保存在应用上下文环境中的,也只在一个请求生命周期内有效。在没有应用上下文的环境中,这个对象不可用。

Flask配置对象config

@app.route('/')
def index():g.db='mysql'returnrender_template('hello.html')

在模版中使用:

<p>DB:{{g.db}}</p>

(4)Flask配置对象config
导入的配置信息,就保存在”app.config”对象中。这个配置对象在模板中也可以访问。
“config”是全局对象,离开了请求生命周期也可以访问。

<p>Host:{{config.DEBUG}}</p>

Flask自定义变量
除了Flask提供的标准上下文变量和函数,我们还可以自己定义。

from flask import current_app@app.context_processor
def appinfo():return dict(appname=current_app.name)

函数返回的是一个字典,里面有一个属性”appname”,值为当前应用的名称。我们曾经介绍过,这里的”current_app”对象是一个定义在应用上下文中的代理。函数用”@app.context_processor”装饰器修饰,它是一个上下文处理器,它的作用是在模板被渲染前运行其所修饰的函数,并将函数返回的字典导入到模板上下文环境中,与模板上下文合并。然后,在模板中”appname”就如同上节介绍的”request”, “session”一样,成为了可访问的上下文对象。我们可以在模板中将其输出:

<p>Current App is:{{appname}}</p>

Flask自定义函数
同理我们可以自定义上下文函数,只需将上例中返回字典的属性指向一个函数即可,下面我们就来定义一个上下文函数来获取系统当前时间:

import time
@app.context_processor
def get_current_time():def get_time(timeFormat="%b %d, %Y - %H:%M:%S"):return time.strftime(timeFormat)return dict(current_time=get_time)

在模版中使用:

<p>Current Time is:{{current_time()}}</p>
<p>Current Day is:{{current_time("%Y-%m-%d")}}</p>

上下文处理器
Flask 上下文处理器自动向模板的上下文中插入新变量。上下文处理器在模板渲染之前运行,并且可以在模板上下文中插入新值。上下文处理器是一个返回字典的函数,这个字典的键值最终将传入应用中所有模板的上下文:

@app.context_processor
def inject_user():return dict(user=g.user)

上面的上下文处理器使得模板可以使用一个名为 user ,值为 g.user 的变量。 不过这个例子不是很有意思,因为 g 在模板中本来就是可用的,但它解释了上下文处理器是如何工作的。
变量不仅限于值,上下文处理器也可以使某个函数在模板中可用(由于 Python 允许传递函数):

@app.context_processor
def utility_processor():def format_price(amount, currency=u'€'):return u'{0:.2f}{1}.format(amount, currency)return dict(format_price=format_price)

上面的上下文处理器使得 format_price 函数在所有模板中可用:

{{ format_price(0.33) }}

标准过滤器
过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,这就用到了过滤器。 过滤器的使用方式为:变量名 | 过滤器。 过滤器名写在变量名后面,中间用 | 分隔。如:{{variable | capitalize}},这个过滤器的作用:把变量variable的值的首字母转换为大写,其他字母转换为小写。
这些过滤器在 Jinja2 中可用,也是 Jinja2 自带的过滤器:
tojson()
这个函数把给定的对象转换为 JSON 表示,如果你要动态生成 JavaScript 这里有一个非常有用的例子。
注意 script 标签里的东西不应该被转义,因此如果你想在 script 标签里使用它, 请使用 |safe 来禁用转义,:

<script type=text/javascript>doSomethingWith({{ user.username|tojson|safe }});
</script>

常用过滤器
字符串操作:
safe:禁用转义;

{{ 'hello' | safe }}

capitalize:把变量值的首字母转成大写,其余字母转小写;

{{ 'hello' | capitalize }}

lower:把值转成小写;

{{ 'HELLO' | lower }}

upper:把值转成大写;

{{ 'hello' | upper }}

title:把值中的每个单词的首字母都转成大写;

{{ 'hello' | title }}

trim:把值的首尾空格去掉;

{{ ' hello world ' | trim }}

reverse:字符串反转;

{{ 'olleh' | reverse }}

format:格式化输出;

{{ '%s is %d' | format('name',17) }}

striptags:渲染之前把值中所有的HTML标签都删掉;

{{ 'hello' | striptags }}

列表操作
first:取第一个元素

{{ [1,2,3,4,5,6] | first }}

last:取最后一个元素

{{ [1,2,3,4,5,6] | last }}

length:获取列表长度

{{ [1,2,3,4,5,6] | length }}

sum:列表求和

{{ [1,2,3,4,5,6] | sum }}

sort:列表排序

{{ [6,2,3,1,5,4] | sort }}

控制自动转义
自动转义的概念是自动转义特殊字符。 HTML (或 XML ,因此也有 XHTML )意义下的特殊字符是 & , > , < , " 以及 ’ 。因为这些字符在文档中表示它们特定的含义,如果你想在文本中使用它们,应该把它们替换成相应的“实体”。不这么做不仅会导致用户疲于在文本中使用这些字符,也会导致安全问题。
虽然你有时会需要在模板中禁用自动转义,比如在页面中显式地插入 HTML , 可以是一个来自于 markdown 到 HTML 转换器的安全输出。
有三种可行的解决方案:

  • 在传递到模板之前,用 Markup 对象封装 HTML字符串。一般推荐这个方法。
  • 在模板中,使用 |safe 过滤器显式地标记一个字符串为安全的 HTML ( {{ myvariable|safe }} )。
  • 临时地完全禁用自动转义系统。
  • 在模板中禁用自动转义系统,可以使用 {%autoescape %} 块:
{% autoescape false %}<p>autoescaping is disabled here<p>{{ will_not_be_escaped }}
{% endautoescape %}

注册过滤器
如果你要在 Jinja2 中注册你自己的过滤器,你有两种方法。你可以把它们手动添加到应用的 jinja_env 或者使用 template_filter() 装饰器。
下面两个例子作用相同,都是反转一个对象:

@app.template_filter('reverse')
def reverse_filter(s):return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter

在使用装饰器的情况下,如果你想以函数名作为过滤器名,参数是可选的。注册之后, 你可以在模板中像使用 Jinja2 内置过滤器一样使用你的过滤器,例如你在上下文中有一个名为 mylist 的 Python 列表:

{% for x in mylist | reverse %}
{% endfor %}

3 Jinja2模版语法

3.1 模版内部变量

可以使用点( . )来访问变量的属性,作为替代,也可以使用所谓的“下标”语 法( [])。下面的几行效果是一样的:

{{ foo.bar }}
{{ foo['bar'] }}

如果你访问标签 里的不带括号的变量。
如果变量或属性不存在,会返回一个未定义值。你可以对这类值做什么取决于应用的配 置,默认的行为是它如果被打印,其求值为一个空字符串,并且你可以迭代它,但其它 操作会失败。

为方便起见,Jinja2 中 foo.bar 在 Python 层中做下面的事情:
检查 foo 上是否有一个名为 bar 的属性。
如果没有,检查 foo 中是否有一个 ‘bar’ 项 。
如果没有,返回一个未定义对象。

foo[‘bar’] 的方式相反,只在顺序上有细小差异:
检查在 foo 中是否有一个 ‘bar’ 项。
如果没有,检查 foo 上是否有一个名为 bar 的属性。
如果没有,返回一个未定义对象。
如果一个对象有同名的项和属性,这很重要。此外,有一个 attr() 过滤 器,它只查找属性。

3.2 注释和空白控制

注释
{# … #} 对于未包含在模板输出中的注释
#。。。##注释行语句

空白控制
默认配置中,模板引擎不会对空白做进一步修改,所以每个空白(空格、制表符、换行符 等等)都会原封不动返回。如果应用配置了 Jinja 的 trim_blocks ,模板标签后的 第一个换行符会被自动移除。
此外,你也可以手动剥离模板中的空白。当你在块(比如一个 for 标签、一段注释或变 量表达式)的开始或结束放置一个减号( - ),可以移除块前或块后的空白:

{% for item in seq -%}{{ item }}
{%- endfor %}

这会产出中间不带空白的所有元素。如果 seq 是 1 到 9 的数字的列表, 输出会是123456789
如果开启了 行语句 ,它们会自动去除行首的空白。
注意:标签和减号之间不能有空白。
有效的:

{%- if foo -%}...{% endif %}

转义
有时想要或甚至必要让 Jinja 忽略部分,不会把它作为变量或块来处理。例如,如果 使用默认语法,你想在在使用把 {{ 作为原始字符串使用,并且不会开始一个变量 的语法结构,你需要使用一个技巧。
最简单的方法是在变量分隔符中( {{ )使用变量表达式输出:

{{ '{{' }}

对于较大的段落,标记一个块为 raw 是有意义的。例如展示 Jinja 语法的实例, 你可以在模板中用这个片段:

{% raw %}<ul>{% for item in seq %}<li>{{ item }}</li>{% endfor %}</ul>
{% endraw %}

3.3 控制结构

控制结构指的是所有的那些可以控制程序流的东西 —— 条件(比如 if/elif/ekse )、 for 循环、以及宏和块之类的东西。控制结构在默认语法中以 {% … %} 块的形式 出现。
for循环
遍历序列中的每项。例如,要显示一个由 users` 变量提供的用户列表:

<h1>Members</h1>
<ul>
{% for user in users %}<li>{{ user.username|e }}</li>
{% endfor %}
</ul>

因为模板中的变量保留它们的对象属性,可以迭代像 dict 的容器:

<dl>
{% for key, value in my_dict.iteritems() %}<dt>{{ key|e }}</dt><dd>{{ value|e }}</dd>
{% endfor %}
</dl>

注意:无论如何字典通常是无序的,所以你可能需要把它作为一个已排序的列表传入 到模板或使用 dictsort 过滤器。
在一个 for 循环块中你可以访问这些特殊的变量:

变量 描述
loop.index 当前循环迭代的次数(从 1 开始)
loop.index0 当前循环迭代的次数(从 0 开始)
loop.revindex 到循环结束需要迭代的次数(从 1 开始)
loop.revindex0 到循环结束需要迭代的次数(从 0 开始)
loop.first 如果是第一次迭代,为 True 。
loop.last 如果是最后一次迭代,为 True 。
loop.length 序列中的项目数。
loop.cycle 在一串序列间期取值的辅助函数。见下面的解释。

在 for 循环中,可以使用特殊的 loop.cycle 辅助函数,伴随循环在一个字符串/变 量列表中周期取值:

{% for row in rows %}<li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}

如果因序列是空或者过滤移除了序列中的所有项目而没有执行循环,你可以使用 else 渲染一个用于替换的块:

<ul>
{% for user in users %}<li>{{ user.username|e }}</li>
{% else %}<li><em>no users found</em></li>
{% endfor %}
</ul>

if条件判断
Jinja 中的 if 语句可比 Python 中的 if 语句。在最简单的形式中,你可以测试 一个变量是否未定义,为空或 false:

{% if kenny.sick %}Kenny is sick.
{% elif kenny.dead %}You killed Kenny!  You bastard!!!
{% else %}Kenny looks okay --- so far
{% endif %}


宏类似常规编程语言中的函数。它们用于把常用行为作为可重用的函数,取代 手动重复的工作。
这里是一个宏渲染表单元素的小例子:

{% macro input(name, value='', type='text', size=20) -%}<input type="{{ type }}" name="{{ name }}" value="{{value|e }}" size="{{ size }}">
{%- endmacro %}

在命名空间中,宏之后可以像函数一样调用:

<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>

在宏内部,你可以访问三个特殊的变量:

变量 说明
varargs 如果有多于宏接受的参数个数的位置参数被传入,它们会作为列表的值保存在 varargs 变量上。
kwargs 同 varargs ,但只针对关键字参数。所有未使用的关键字参数会存储在 这个特殊变量中。
caller 如果宏通过 call 标签调用,调用者会作为可调用的宏被存储在这个 变量中。

宏也可以暴露某些内部细节。下面的宏对象属性是可用的:

属性 说明
name 宏的名称。 {{ input.name }} 会打印 input 。
arguments 一个宏接受的参数名的元组。
defaults 默认值的元组。
catch_kwargs 如果宏接受额外的关键字参数(也就是访问特殊的 kwargs 变量),为 true 。
catch_varargs 如果宏接受额外的位置参数(也就是访问特殊的 varargs 变量),为 true 。
caller 如果宏访问特殊的 caller 变量且由 call 标签调用,为 true 。如果一个宏的名称以下划线开始,它不是导出的且不能被导入。

用法示例:
可以把宏单独抽取出来,封装成html文件,其它模板中导入使用。
如:文件名可以自定义mymacro.html

#单独的html宏
{% macro function() %}<input type="text" name="username" placeholde="Username"><input type="password" name="password" placeholde="Password"><input type="submit">
{% endmacro %}#在其它模板文件中先导入,再调用
{% import 'macro.html' as func %}
{% func.function() %}

宏提供了一种模块化代码的方式:
(1)在macro.html中定义宏函数

{# myapp/templates/macros.html #}{% macro nav_link(endpoint, text) %}
{% if request.endpoint.endswith(endpoint) %}<li class="active"><a href="{{ url_for(endpoint) }}">{{text}}</a></li>
{% else %}<li><a href="{{ url_for(endpoint) }}">{{text}}</a></li>
{% endif %}
{% endmacro %}

(2)在其他html文件中导入宏,然后使用

{# myapp/templates/layout.html #}
{% from "macros.html" import nav_link with context %}
<!DOCTYPE html>
<html lang="en"><head>{% block head %}<title>My application</title>{% endblock %}</head><body><ul class="nav-list">{{ nav_link('home', 'Home') }}{{ nav_link('about', 'About') }}{{ nav_link('contact', 'Get in touch') }}</ul>{% block body %}{% endblock %}</body>
</html>

注意:

  • 从 x 导入 y 语句采用了 x 的相对路径。如果我们的模板是 myapp/templates/user/blog.html,我们可以在使用 from “…/macros.html” 导入 nav_link。
  • 当我们说 {% from … import … with context %} 的时候,就是告诉 Jinja 这些变量对宏也可用。

宏调用
在某些情况下,需要把一个宏传递到另一个宏。为此,可以使用特殊的 call 块。 下面的例子展示了如何让宏利用调用功能:

{% macro render_dialog(title, class='dialog') -%}<div class="{{ class }}"><h2>{{ title }}</h2><div class="contents">{{ caller() }}</div></div>
{%- endmacro %}{% call render_dialog('Hello World') %}This is a simple dialog rendered by using a macro anda call block.
{% endcall %}

过滤器
过滤器段允许你在一块模板数据上应用常规 Jinja2 过滤器。只需要把代码用 filter 节包裹起来:

{% filter upper %}This text becomes uppercase
{% endfilter %}

赋值
在代码块中,你也可以为变量赋值。在顶层的(块、宏、循环之外)赋值是可导出的,即 可以从别的模板中导入。
赋值使用 set 标签,并且可以为多个变量赋值:

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}

继承
模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。
{% block top %}``{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
子模板使用extends指令声明这个模板继承自哪。父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()。
extends 标签用于从另一个模板继承。你可以在一个文件中使用多次继承,但是 只会执行其中的一个。
注意:

  • 不支持多继承。
  • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
  • 不能在一个模板文件中定义多个相同名字的block标签。
  • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。
  #父模版定义{% block top %}顶部菜单{% endblock top %}{% block content %}{% endblock content %}{% block bottom %}底部{% endblock bottom %}#子模版使用,先继承,重写对应block部分{% extends 'base.html' %}{% block content %}需要填充的内容{% endblock content %}

常用模版设计模式:
父模板 通常定义一个通用的结构,所有 子模板 都能很好的继承它。在我们的例子中,layout.html 就是一个父模板而其它 .html 文件就是子模板。
templates目录结构如下:

templates/layout.htmlindex.htmlabout.htmlprofile/layout.htmlindex.htmlphotos.htmladmin/layout.htmlindex.htmlanalytics.html

通常有一个顶层的 layout.html,它定义了应用程序的通用布局以及你的网站的每一部分。如果你看看上面的目录的话,你会看到一个顶层的 myapp/templates/layout.html,同样还有 myapp/templates/profile/layout.html 和 myapp/templates/admin/layout.html。最后两个文件继承和修改第一个文件。
在父模板中,我们能定义由子模板来填充的块。

{# _myapp/templates/layout.html_ #}<!DOCTYPE html>
<html lang="en"><head><title>{% block title %}{% endblock %}</title></head><body>{% block body %}<h1>This heading is defined in the parent.</h1>{% endblock %}</body>
</html>

在子模板中,我们可以扩展父模板并且定义这些块的内容。

{# _myapp/templates/index.html_ #}{% extends "layout.html" %}
{% block title %}Hello world!{% endblock %}
{% block body %}{{ super() }} ##super() 函数让我们渲染父级块的内容。<h2>This heading is defined in the child.</h2>
{% endblock %}


块用于继承,同时作为占位符和用于替换的内容。 模板继承 节中详细地介绍了块。

包含
include 语句用于包含一个模板,并在当前命名空间中返回那个文件的内容渲 染结果:

{% include 'header.html' %}Body
{% include 'footer.html' %}

从 Jinja 2.2 开始,你可以把一句 include 用 ignore missing 标记,这样 如果模板不存在,Jinja 会忽略这条语句。当与 with 或 without context 语句联合使用时,它必须被放在上下文可见性语句 之前 。这里是一些有效的例 子:

{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}

宏、继承、包含区别
宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。
继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。
宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。
包含(include)是直接将目标模板文件整个渲染出来。

3.4 导入上下文行为

默认下,每个包含的模板会被传递到当前上下文,而导入的模板不会。这样做的原因 是导入量不会像包含量被缓存,因为导入量经常只作容纳宏的模块。
无论如何,这当然也可以显式地更改。通过在 import/include 声明中直接添加 with context 或 without context ,当前的上下文可以传递到模板,而且不会 自动禁用缓存。

{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}

参考文献:
http://docs.jinkan.org/docs/flask/quickstart.html#id7
http://docs.jinkan.org/docs/flask/templating.html#jinja

Flask之模版(2)相关推荐

  1. Flask mysql 模版传参_Flask渲染Jinja2模板和传参

    ### Flask渲染Jinja2模板和传参: 1. 如何渲染模板: * 模板放在`templates`文件夹下 * 从`flask`中导入`render_template`函数. * 在视图函数中, ...

  2. Flask——jinja2模版引擎

    文章目录 1 什么是模板引擎? 2 为什么要使用模板引擎? 3 jinja2模板引擎 4 变量 5 语法 变量显示语法 自定义过滤器 for循环: if语句 6 宏 macro 宏的定义 宏的调用 7 ...

  3. flask 继承模版的基本使用

    转载于:https://www.cnblogs.com/wanghaonull/p/6399479.html

  4. flask 继承模版的基本使用1

    转载于:https://www.cnblogs.com/wanghaonull/p/6399492.html

  5. 【Flask教程】Flask开发基础与入门

    一.Flask中的Hello World from flask import Flask app = Flask(__name__) @app.route('/') //路由 def hello_wo ...

  6. flask 渲染jinja2模版和传参

    渲染模版(html文件) A.模版文件(html)放入到template目录下,项目启动的时候会从template目录里查找, B.从flask中导入"render_tempalte&quo ...

  7. python前端界面模板_Python编程flask使用页面模版的方法

    在flask中可以像go和angular那样使用页面模版(template),可以将HTML页面显示进行模版化,通过参数传递与页面进行数据交互. 概要信息 事前准备:flask liumiaocn:f ...

  8. Flask 模版(四)- 时间 Flask-Moment

    服务器使用与地区无关的统一时间 UTC,将UTC转换为浏览器当地时间,可以用moment.js完成这个过程. 我们使用Flask-Moment扩展将moment.js集成到Jinja2模版中. 在主程 ...

  9. Flask框架的学习——04—(模版继承、静态文件的配置、豆瓣APP界面案例实现)

    1.模版继承 Flask中的模板可以继承,通过继承可以把模板中许多重复出现的元素抽取出来,放在父模板中,并且父模板通过定义block给子模板开一个口,子模板根据需要,再实现这个block,假设现在有一 ...

最新文章

  1. tomcat线程释放时间_详解tomcat的连接数与线程池
  2. 2018多校1 hdu6298 6300 6308
  3. Mac 编译报错 symbol(s) not found for
  4. image 微信小程序flex_第三天学习微信小程序开发总结
  5. 小学期实践心得(1)
  6. Spring Boot实践——Spring AOP实现之动态代理
  7. formData:解决formData使用append追加后console仍为空
  8. 【优化算法】灰狼混合布谷鸟优化算法(GWO_CS)【含Matlab源码 1468期】
  9. 强制客户端更新Silverlight XAP文件方法汇总
  10. android删除sd卡照片恢复,手机内存清理方法及照片误删恢复方法 手机党必备
  11. 致敬不凡·最美的星火:国产飞腾CPU研发力量
  12. Unity Mesh(五) Mesh 立方体Cube贴图以及六个面分别贴不同的图片
  13. HTML按钮样式,CSS精美按钮
  14. TextView设置MaxLength
  15. Linux 文件解压缩及权限管理
  16. Maven将有依赖其它jar包的项目打包成jar包(路径依赖),一步到位。
  17. edge无法登录账户_最近发现微软账户登录不上,edge,等等,都是?怎么回事?...
  18. python远程连接ssh_Python实现SSH连接远程服务器
  19. UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xbd in position 5: illegal multibyte sequence
  20. 基础概念之电路板的概念

热门文章

  1. 洗地机有哪些牌子比较好、最好的智能洗地机品牌推荐
  2. office-Excel-表格中相同项进行求和
  3. Windows下使用cmd进入MySQL
  4. 本文99.99%解答了你对CMMI V2.0的疑问,值得收藏!
  5. RedHat Linux 8中 Apache服务
  6. vector定义二维数组
  7. 在线诉讼区块链证据规则的理论逻辑与制度体系
  8. Vue小案例——图书列表
  9. 偶数分解成质数c语言,C++将偶数分解为质数
  10. CMake通过外部传参执行不同逻辑的方案比如瑞芯微(1126)地平线(horizon)