Flask之模板
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除

目录
一、模板的基本用法
1.1、创建模板
1.2、模板语法
1.3、渲染模板
二、模板辅助工具
2.1、上下文
2.2、全局对象
2.3、过滤器
2.4、测试器
2.5、模板环境对象
三、模板组织结构
3.1、局部模板
3.2、宏
3.3、模板继承
四、模板进阶实践
4.1、空白控制
4.2、加载静态文件
4.3、消息闪现
4.4、自定义错误页面
4.5、JavaScript和CSS中的Jinja2
致谢
一、模板的基本用法
1.1、创建模板
假设我们要编写一个用户的电影清单页面(用户信息、用户收藏的电影列表等)。首先创建一些虚拟数据用于测试显示效果:
user = {'username': 'Grey Li','bio': 'A boy who loves movies and music',}movies = [{'name': 'My Neighbor Totoro', 'year': '1988'},{'name': 'Three Colours trilogy', 'year': '1993'},{'name': 'John Harrison', 'year': '1994'},{'name': 'Perfect Blue', 'year': '1997'},]
在templates目录下创建一个watchlist.html作为模板文件,然后使用Jinja2支持的语法在模板中操作这些变量:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>{{ user.username }}'s Watchlist</title></head><body><a href="{{ url_for('index') }}">$larr; Return</a><h2>{{ user.username }}</h2>{% if user.bio %}<i>{{ user.bio }}</i>{% else %}<i>This user has not provided a bio</i>{% endif %}{# 下面是电影清单(这是注释) #}<h5>{{ user.username }}'s Watchlist ({{ movies|length }}):</h5><ul>{% for moive in movies %}<li>{{ movie.name }} - {{ moive.year }}</li>{% endfor %}</ul></body></html>
Jinja2里常见的三种定界符:
(1)语句
比如if判断、for循环等:
{% ... %}
(2)表达式
比如字符串、变量、函数调用等:
{{ ... }}
(3)注释
{# ... #}
另外,在模板中Jinja2 支持用"."获取变量的属性,比如user字典中的username键值通过"."获取,即user.username,在效果上等同于user['username']。
1.2、模板语法
Jinja2运行在模板中使用大部分Python对象,比如字符串、列表、字典、元组、整型、浮点型、布尔值等。支持基本的运算符号(+、-、*、/等)、比较符号(==、 !=等)、逻辑符号(and、or、not等)以及in、is、None和布尔值(True、False)。
还提供多种控制结构来控制模板的输出,其中for和if是最常用的两种。语句使用{% ... %}标识,尤其注意,在语句结束的地方,我们必须添加结束标签:
{% if user.bio %}<i>{{ user.bio }}</i>{% else %}<i>This user has not provided a bio.</i>{% endif %}
和Python一样,for语句用来迭代一个序列:
<ul>{% for moive in movies %}<li>{{ movie.name }} - {{ moive.year }}</li>{% endfor %}</ul>
在for循环内,Jinja2提供了多个特殊变量,常用的循环变量:
| 变量名 | 说明 |
|---|---|
| loop.index | 当前迭代数(从1开始计数) |
| loop.index0 | 当前迭代数(从0开始计数) |
| loop.revindex | 当前反向迭代数(从1开始计数) |
| loop.revindex0 | 当前反向迭代数(从0开始计数) |
| loop.first | 如果是第一个元素,则为True |
| loop.last | 如果是最后一个元素,则为True |
| loop.previtem | 上一个迭代的条目 |
| loop.nextitem | 下一个迭代的条目 |
| loop.length | 序列包含的元素数量 |
1.3、渲染模板
渲染一个模板就是执行模板中的代码,并传入所有在模板中使用的变量,渲染后的结果就是我们要返回给客户端的HTML响应。使用Flask提供的渲染函数render_template():
from flask import Flask,render_template...@app.route('/watchlist')def watchlist():return render_template('watchlist.html', user=user, movies=movies)
除了render_template()函数,Flask还提供了一个render_template_string()函数用来渲染模板字符串。
其他类型的变量通过相同的方式传入。示例:
<p>这是列表my_list的第一个元素:{{ my_list[0] }}</p><p>这是元组my_tuple的第一个元素:{{ my_tuple[0] }}</p><p>这是字典my_dict的键为name的值:{{ my_dict['name'] }}</p><p>这是函数my_func的返回值:{{ my_func() }}</p><p>这是对象my_object调用某方法的返回值:{{ my_object.name }}</p>
二、模板辅助工具
为了方便测试,在templates目录下创建一个根页面模板index.html:
from flask import render_template@app.route('/')def index():return render_template('index.html')
2.1、上下文
除了渲染时传入变量,也可以在模板中定义变量,使用set标签:
{% set navigation = [('/','Home'),('/about','About')] %}
也可以将一部分模板数据定义为变量,使用set和endset标签声明开始和结束:
{% set navigation %}<li><a href="/">Home</a><li><a href="/about">About</a>{% endset %}
2.1.1、内置上下文变量
Flask在模板上下文中提供了一些内置变量,可以在模板中直接使用:
| 变量 | 说明 |
|---|---|
| config | 当前的配置对象 |
| request | 当前的请求对象,在已激活的请求环境下可用 |
| session | 当前的会话对象,在已激活的请求环境下可用 |
| g | 与请求绑定的全局变量,在已激活的请求环境下可用 |
2.1.2、自定义上下文
如果多个模板都需要使用同一变量,设置一个模板全局变量以供使用。Flask提供了一个app.context_processor装饰器,可以用来注册模板上下文处理函数,完成统一传入变量操作:
@app.context_processordef inject_foo():foo = 'I am foo.'return dict(foo=foo)
当我们调用render_template()函数渲染任意一个模板时,所有使用app.context_processor装饰器注册的模板上下文处理函数都会被执行,这些函数的返回值会被添加到模板中,因此我们可以在模板中直接使用foo变量。
除了使用app.context_processor装饰器,也可以直接将其作为方法调用,传入模板上下文处理函数:
...def inject_foo():foo = 'I am foo.'return dict(foo=foo)app.context_processor(inject_foo)
使用lambda简化为:
app.context_processor(lambda:dict(foo='I am foo.'))
2.2、全局对象
全局对象值在所有模板中都可以直接使用的对象,包括在模板中导入的模板。
2.2.1、内置全局函数
Jinja2在模板中默认提供了一些全局函数(部分):
| 函数 | 说明 |
|---|---|
| range([satrt,]stop[,step]) | 和Python中的range()用法相同 |
| lipsum(n=5,html=True,min=20,max=100) | 生成随机文本,可以在测试时用来填充页面。默认生成5段HTML文本,每段包含20-100个单词 |
| dict(**items) | 和Python中的dict()用法相同 |
Flask也在模板中内置了两个全局函数:
| 函数 | 说明 |
|---|---|
| url_for() | 用于生成URL的函数 |
| get_flashed_messages() | 用于获取flash消息的函数 |
url_for()用来获取URL,用法和在Python脚本中相同。在实际的代码中,这个URL使用url_for()生成,传入index视图的端点:
<a href="{{ url_for('index')}}">← Return</a>
2.2.2、自定义全局函数
使用app.template_global装饰器直接将函数注册为模板全局函数。(仅用于注册全局函数)
# 把bar()函数注册为模板全局函数@app.template_globaldef bar():return 'I am bar'
默认使用函数的原名称传入模板,在app.template_global()装饰器中使用name参数可以指定一个自定义名称。
2.3、过滤器
过滤器修改和过滤变量值的特殊函数,过滤器和变量用一个竖线(管道符号)隔开,需要参数的过滤器可以像函数一样使用括号传递。
{{ name|title }}# 这会将name变量的值标题化,相当于Python中调用name.title()。{{ movies|length }}# 获取moives长度,相当于Python值调用len(moives)
另一种方法是将过滤器作用于部分模板数据,使用filter标签和endfilter标签声明开始和结束:
{% filter upper %}This text bacomes uppercase.{% endfilter %}
2.3.1、内置过滤器(部分)
| 过滤器 | 说明 |
|---|---|
| escape(s) | 转义HTML,别名为e |
| first(seq) | 返回序列的第一个元素 |
| last(seq) | 返回序列的最后一个元素 |
| length(object) | 返回变量的长度 |
| random(seq) | 返回序列中的随机元素 |
在使用过滤器时,列表中过滤器函数的第一个参数表示过滤的变量值(value)或字符串(s),即竖线符号左侧的值,其他的参数可以通过括号传入。
过滤器可以叠加使用:
# 为变量name设置默认值,并将其标题化<h1>Hello,{{ name|default('陌生人')|title }}!</h1>
根据Flask设置,Jinja2会自动对模板中的变量进行转义,因此我们不需要手动使用escape过滤器或调用excape()函数对变量进行转义。若想避免转义,将变量作为HTML解析,可以对变量使用safe过滤器或者在渲染前将变量转换为Markup对象:(不要对用户输入的内容使用safe,容易被攻击)
# safe过滤器{{ sanitied_text|safe }}# 转换为markup对象from flask import Markup@app.route('/hello')def hello():text = Markup('<h1>Hello,Flask!</h1>')return render_template('index.html',text=text) # 这时可以在模板中直接使用{{ text }}
2.3.2、自定义过滤器
使用app.template_filter()装饰器可以注册自定义过滤器:例注册一个musical过滤器:
from flask import Markup@app.template_filter()def musical(s):return s + Markup(' ♫')
与注册全局函数一样,可以在app.template_filter()中使用name关键字设置过滤器的名称,默认使用函数名称。用法与其他过滤器相同。
2.4、测试器
在Jinja2中,测试器(Test)是一些用来测试变量或表达式,返回布尔值的特殊函数。
# number测试器用来判断一个变量或表达式是否为数字,我们使用is连接变量和测试器:{% if age is number %}{{ age * 365 }}{% else %}无效的数字{% endif %}
2.4.1、内置测试器(部分)
| 测试器 | 说明 |
|---|---|
| callable(object) | 判断对象是否可被调用 |
| defined(value) | 判断变量是否已定义 |
| undefined(value) | 判断变量是否未定义 |
| none(value) | 判断变量是否None |
| number(value) | 判断变量是否是数字 |
| string(value) | 判断变量是否字符串 |
| sequence(value) | 判断变量是否是序列,比如字符串、列表、元组 |
| iterable(value) | 判断变量是否可迭代 |
| mapping(value) | 判断变量是否是匹配对象,比如字典 |
| sameas(value,other) | 判断变量与 other是否指向相同的内存地址 |
使用测试器时,is的左侧是测试器函数的第一个参数(value),其他参数可以添加括号传入,也可以在右侧使用空格连接,以sameas为例:
{% if foo is sameas(bar) %}...# 等同于{% if foo is sameas bar %}...
2.4.2、自定义测试器
使用app.template_test()装饰器来注册一个自定义测试器。例子:
@app.template_testdef baz(n):if n == 'baz':return Truereturn False
同样,可以使用关键字name指定名称,默认为函数名称
2.5、模板环境对象
在Jinja2中,渲染行为由jinja2.Environment类控制,所有的配置选项、上下文变量、全局函数、过滤器和测试器都存储在Environment实例上。当与Flask结合后,我们直接使用Flask创建的Environment对象,它存储在app.jinja_env属性上(其可以更改Jinja2设置)
#使用variable_start_string和variable_end_string自定义变量定界符的开始和结束app = Flask(__name__)app.jinja_env.variable_start_string = '[['app.jinja_env.variable_end_string = ']]'
模板环境中的全局函数、过滤器和测试器分别存储在Environment对象的globals、filters和tests属性中,都是字典对象。
2.5.1、添加自定义全局对象
和app.template_global()装饰器不同,直接操作globals字典允许我们传入任意Python对象,而不仅仅是函数,类似上下文处理函数的作用。
# 添加全局函数bar和全局变量foo:def bar():return 'I am bar'foo = 'I am foo'app.jinja_env.globals['bar'] = barapp.jinja_env.globals['foo'] = foo
2.5.2、添加自定义过滤器
# 添加自定义过滤器smilingdef smiling(s):return s + ':)'app.jinja_env.filters['smiling'] = smiling
2.5.3、添加自定义测试器
# 添加自定义测试器bazdef baz(n):if n == 'baz':return Truereturn Falseapp.jinja_env.tests['baz'] = baz
三、模板组织结构
Jinja2还提供了一些工具来在宏观上组织模板内容。更好实践DRY(Don't Repeat Yourself)原则
3.1、局部模板
当多个独立模板都会使用同一块HTML代码时,我们把这部分代码抽离出来,存储到局部模板中。可以避免重复又方便统一管理。
我们使用include标签插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置:
{% include '_banner.html' %}
为了和普通模板区分开,局部模板命名通常以一个下划线开始
3.2、宏
宏(macro)是Jinja2中的特性,类似Python中的函数。使用宏可以将一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。
为了便于管理,通常把宏存储到单独文件中(macros.html)。
使用macro和endmacro标签声明宏的开始和结束,在开始标签中定义宏的名称和接收的参数:
{% macro qux(amount=1) %}{% if amount ==1 %}I am qux.{% elif amount > 1 %}We are quxs.{% endif %}{% endmacro %}
使用时使用import语句导入,然后作为函数调用,传入必要的参数:
{% from 'macros.html' impor qux %}...{{ qux(amount=5) }}
默认情况下包含(include)一个局部模板会传递当前上下文到局部模板,但导入(import)不会。换句话:当我们使用render_template()函数渲染一个foo.html模板时,这个foo.html的模板上下文中包含下列对象:
- Flask使用内置的模板上下文处理函数提供的g、session、config、request。
- 扩展使用内置的模板上下文处理函数提供的变量
- 自定义模板上下文处理器传入的变量
- 使用render_template()函数传入的变量
- Jinja2和Flask内置及自定义全局对象
- Jinja2内置及自定义过滤器
- Jinja2内置及自定义测试器
使用include标签插入的局部模板同样可以使用上述。而导入一个并非被直接渲染的模板,这个模板仅包含下列对象:
- Jinja2和Flask内置及自定义全局对象
- Jinja2内置及自定义过滤器
- Jinja2内置及自定义测试器
因此,若想在导入的宏中使用第一个列表中的2,3,4项,就需要在导入时显式地使用with context声明传入当前模板的上下文:
{% from 'macros.html' impor foo with context %}
3.3、模板继承
Jinja2的模板允许定义一个基模板,把像导航栏、页脚等通用部分放在基模板中。
3.3.1、编写基模板
基模板存储程序页面固定部分,通常被命名为base.html或layout.html。
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>{% block title %}Template - HelloFlask{% endblock %}</title>{% block styles %}{% endblock %}</head><body><nav><ul><li><a href="{{ url_for('index') }}">Home</a></li></ul></nav><main>{% block content %}{% endblock %}</main><footer>{% block footer %}...{% endblock %}</footer>{% block scripts %}{% endblock %}</body></html>
当子模板继承基模板后,会自动包含基模板的内容和结构。在基模板定义块(block),在子模板中可以通过定义同名的块来执行继承操作。
块的开始和结束用block和endblock标签声明,可以嵌套。为了避免块的混乱,块的结束标签可以指明块名,确保前后名称一致。
{% block body %}...{% endblock body %}
3.3.2、编写子模板
在子模板中只需要对特定的块进行修改。
{% extends 'base.html' %}{% from 'macro.html' import qux %}{% block content %}{% set name='baz' %}<h1>Template</h1><ul><li><a href="{{ url_for('watchlist') }}">Watchlist</a></li><li>Filter:{{ foo|musical }}</li><li>Global:{{ bar() }}</li><li>Test:{% if name is baz %}I am baz.{% endif %}</li><li>Macro:{{ qux(amount=5) }}</li></ul>{% endblock %}
extends标签声明扩展基模板,且必须是子模板的第一个标签。
我们在基模板中定义了四个块,在子模板中,我们可以对父模板中的块执行两种操作:
(1)覆盖内容
在子模板创建同名的块,会使用子块的内容覆盖父块的内容。
(2)追加内容
使用Jinja2提供的super()函数进行声明,这会向父块添加内容,例如(向基模板中的styles块追加一行<style>样式定义:
{% block styles %}{{ super() }}<style>.foo{color:red;}</style>{% endblock %}
四、模板进阶实践
模板在Flask程序中的常见应用(加载静态文件和自定义错误页面)
4.1、空白控制
在实际输出的HTML文件中模板中的Jinja2语句、表达式和注释会保留移除后的空行。
{% if user.bio %}<i>{{ user.bio }}</i>{% else %}<i>This user has not provided a bio.</i>{% endif %}# 实际输出的HTML代码:<i>{{ user.bio }}</i><i>This user has not provided a bio.</i>
若想在渲染时自动去掉这些空行,在定界符内侧添加减号。{%- endfor %}会移除该语句前的空白,同理,右边可以移除该语句后面的空白
{% if user.bio -%}<i>{{ user.bio }}</i>{% else -%}<i>This user has not provided a bio.</i>{%- endif %}# 现在输出的Html:<i>{{ user.bio }}</i><i>This user has not provided a bio.</i>
除了使用减号,还可以使用模板环境对象提供的trim_blocks(删除语句后的第一个空行)和lstrip_blocks属性(删除语句所在行之前的空格和制表符)设置。
app.jinja_env.trim_blocks = Trueapp.jinja_env.lstrip_blocks = True# trim_blocks值的block指的是使用{%...%}界定的代码块,与继承的块无关
宏内的空白制作不受terim_blocks和lstrip_blocks属性控制,我们需要手动设置:
{% macro qux(amount=1) %}{% if amount ==1 -%}I am qux.{% elif amount > 1 -%}We are quxs.{%- endif %}{% endmacro %}
事实上,我们没必要严格控制HTML输出,因为多余的空白并不影响浏览器的解析。
4.2、加载静态文件
在Flask程序中,默认将静态文件存储在与主脚本同级目录的static文件夹中。
使用url_for()函数获取静态文件的URL在HTML模板中引用。Flask内置了用于获取静态文件的视图函数,端点值为static,它的默认URL规则为/static/path:filename,URL变量filename是相对于static文件夹根目录的文件路径。
提示:若想使用其他文件夹来存储静态文件,可以在实例化Flask类时使用static_folder参数指定。在实例化Flask类时使用static_url_path参数则可以自定义静态文件的URL路径。
<img src="{{ url_for('static',filename='avatar.jpg') }}" width="50">
另外,我们还创建了一个存储CSS规则的styles.css文件,加载方法:
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='style.css') }}">
4.2.1、添加Favicon
前两章运行的时候,会看到一条404状态请求记录,请求的URL是/favicon.ico
127.0.0.1 - - [08/Feb/2024 18:30:12] "GET /Favicon.ico HTTP/1.1" 404 -
Favicon.icon文件指的是Favicon(收藏夹头像/网站头像),又称shortcut.icon、tab icon、website.icon或是bookmark.icon。作为网站的特殊标记。
将Favicon文件放在static目录下,Flask中静态文件的默认路径是/static/filename,为了正确返回Favicon,我们可以显式的在HTML页面中声明Favicon的路径。
<link rel="icon" type="image/x-icon" href="{{ url_for('static',filename='favicon.ico') }}">
4.2.2、使用CSS框架
自写CSS比较麻烦,以Bootstrap为例,访问官网下下载相应的资源文件,然后分类放到static目录下。
{% block styles %}<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.min.css') }}">{% endblock %}...{% block scripts %}<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script><script src="{{ url_for('static',filename='js/popper.min.js') }}"></script><script src="{{ url_for('static',filename='js/bootstrap.min.js') }}"></script>{% endblock %}
若是想简化开发过程,那么从CDN加载是更方便的做法。从CDN加载时,只需要将相应的URL替换为CDN提供的资源URL,例:
{% block styles %}<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap-grid.css" rel="stylesheet">{% endblock %}
4.2.3、使用宏加载静态资源
创建一个专门用于加载静态资源的宏,例如:
{% macro static_file(type,filename_or_url,local=True) %}{% if local %}{% set filename_or_url = url_for('static',filename_or_url) %}{% endif %}{% if type == 'css' %}<link rel="stylesheet" href="{{ filename_or_url }}" type="text/css">{% elif type == 'js' %}<script type="text/javascript" src="{{ filename_or_url }}"></script>{% elif type == 'icon' %}<link rel="icon" href="{{ filename_or_url }}" >{% endif %}{% endmacro %}
在模板 中导人宏后,只需在调用时传入静态资源 别和文件路径就会获得完整的资源加载语句
# 使用它加载 css 文件的示例static_file('css','css/bootstrap.min.css')# 使用它加载CDN资源static_file ('css','https://maxcdn.../css/bootstrap.min.css’,local=False)
4.3、消息闪现
Flask提供的flash()函数用来“闪现”需要显示给用户的信息,比如当用户登录成功后显示“欢迎回来!”。
使用功能flash()函数发送的消息会存储在session中(所有我们需要为程序设置密钥。可以通过app.secret_key属性或配置变量SECRET_KEY设置),我们需要在模板中使用全局函数get_flashed_messages()获取消息并将其显示出来。
from flask import Flask, render_template, flash, redirect, url_forapp = Flask(__name__)app.secret_key = 'secret string'@app.route('/flash')def just_flash():flash('I am flash, who is looking for me?')return redirect(url_for('index'))
- 在Python 2.x版本中,如果字符串包含中文或任何非ASCII字符,需要使用
u前缀来声明这个字符串为Unicode字符串。 - 同时,需要在Python文件的首行添加编码声明,通常是
# -*- coding: utf-8 -*-,这告诉Python使用UTF-8编码来解码字符串。 - 这样做可以避免发送中文消息时出现编码问题。
# -*- coding: UTF-8 -*-...@app.route('/flash')def just_flash():flash(u'你好!')return redirect(url_for('index'))
使用get_flashed_messages()函数渲染flash消息:
<main>{% for message in get_flashed_messages() %}<div class="alert">{{ message }}</div>{% endfor %}{% block content %}{% endblock %}</main>
当get_flashed_messages()函数被调用时,session中存储的所有消息都会被移除。发现,重载后的页面不再出现这条消息。
4.4、自定义错误页面
首先创建错误页面的模板文件,可在templates里面创建一个errors子文件夹,最常见的有404和500错误的模板文件。下面是一个404.html模板示例
{% extends 'base.html' %}{% block title %}404 - Page Not Found{% endblock %}{% block content %}<h1>Page Not Found</h1><p>You are lost...</p>{% endblock %}
错误处理函数需要附加app.errorhandler()装饰器,并传入错误状态码作为参数。错误处理函数本身则需要接收异常类作为参数,并在返回值中注明对应的HTTP状态码。当发生错误时,对应的错误处理函数会被调用,它的返回值会作为错误响应的主体。
...@app.errorhandler(404)def page_not_found(e):return render_template('errors/404.html'),404
Werkzeug内置的HTTP异常类的常用属性
| 属性 | 说明 |
|---|---|
| code | 状态码 |
| name | 原因短语 |
| description | 错误描述,另外使用get_description()方法还可以获取HTML格式的错误描述代码 |
4.5、JavaScript和CSS中的Jinja2
程序变大时,有时我们需要在JavaScript和CSS代码中使用Jinja2提供的变量值,甚至是控制语句。比如通过传入模板的theme_color变量来为页面设置主题色彩,或是根据用户是否登录来决定是否执行某个JavaScript函数
只有使用remder_template()传入的模板文件才会被渲染,若把Jinja2代码写在单独的JavaScript或是CSS文件中,尽管在HTML中引用了它们,也不会被执行,以下是以下Tips:
4.5.1、行内/嵌入式JavaScript/CSS
在HTML中使用<style>和<script>标签来定义这部分CSS和JavaScript代码。不推荐,难以维护
4.5.2、定义为JavaScript/CSS变量
对于想要在JavaScript中获取的数据,如果是元素特定的数据,比如某个文章条目对应的id值,可以通过HTML元素的data-*属性存储。自定义横线后的名称,作为元素上的自定义数据变量,data-id,data-username等。
<span data-id="{{ user.id }}" data-username="{{ user.username }}">{{ user.username }}</span>
在JavaScript中使用DOM元素的dataset属性来获取data-*属性值,如element.dataset.username或使用getAttribute()方法:element.getAttribute('data-username');使用jQuery,直接调用data方法获取:$element.data('username')
对于全局使用的数据,则可在页面中使用嵌入式JavaScript定义变量,如果没法定义为JavaScript变量,就考虑定义为函数:(若使用太多,则考虑将程序转变为Web API。
<script type="text/javascript">var foo = '{{ foo_variable }}';</script># CSS同理<style>:root {--theme-color:{{ theme_color }};--background-url:{{ url_for('static',filename='background.jpg') }}}</style># 在CSS文件中使用var()函数传入变量名即可获取对应的变量值#foo {color: var(--theme-color);}#bar {background: var(--background-url);}
致谢
在此,我要对所有为知识共享做出贡献的个人和机构表示最深切的感谢。同时也感谢每一位花时间阅读这篇文章的读者,如果文章中有任何错误,欢迎留言指正。
学习永无止境,让我们共同进步!!
相关文章:
Flask之模板
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 目录 一、模板的基本用法 1.1、创建模板 1.2、模板语法 1.3、渲染模板 二、模板辅助工具 2.1、上下文 2.2、全局对象 2.3、过滤器 2.4、测试…...
如何优化 Bash 脚本的执行效率?
要优化 Bash 脚本的执行效率,可以考虑以下几个方面: 减少命令执行次数:Bash 脚本中的命令执行是比较耗时的,在可能的情况下,可以尽量减少命令的执行次数。例如,可以将多个命令合并成一个,使用管…...
c语言---循环 、判断基础知识详解
if语句 else离最近的if语句结合。 if语句题目 //1. 判断一个数是否为奇数 //2. 输出1 - 100之间的奇数 #include <stdio.h> int main() {int n 0;scanf("%d", &n);if (n % 2){printf("奇数\n");}else{printf("不是奇数\n"…...
Opencv高级图像处理
文章目录 Opencv高级图像处理图像坐标二值化滤波高斯滤波中值滤波 开闭运算检测霍夫圆检测边缘检测Canny边缘检测findContours区别傅里叶变换-高/低通滤波 直线检测 相机标定视频处理视频格式 模板摄像头处理(带参调节)单图片处理(带参调节&a…...
Linux操作系统学习:day03
内容来自:Linux介绍 视频推荐:[Linux基础入门教程-linux命令-vim-gcc/g -动态库/静态库 -makefile-gdb调试]( 目录 day0317、创建删除目录创建目录删除目录 18、文件的拷贝19、mv 命令20、查看文件内容的相关命令21、给文件创建软连接或硬链接 day03 …...
快排(霍尔排序实现+前后指针实现)(递归+非递归)
前言 快排是很重要的排序,也是一种比较难以理解的排序,这里我们会用递归的方式和非递归的方式来解决,递归来解决是比较简单的,非递归来解决是有点难度的 快排也称之为霍尔排序,因为发明者是霍尔,本来是命名…...
客户端输入网址后发生的全过程解析(协议交互、缓存、渲染)
目录 1. 输入 URL 并按下回车键2. DNS 解析3. TCP 连接4. 发送 HTTP 请求5. 服务器处理请求6. 发送 HTTP 响应7. 浏览器接收响应8. 渲染网页9. 执行脚本10. 处理其他资源11. TLS/SSL 加密(如果使用 HTTPS)握手过程 12. 协议协商和优化 总结 1. 输入 URL …...
未来科技:Web3如何重塑物联网生态系统
随着Web3技术的崛起,物联网(IoT)的发展正迎来一场深刻的变革。本文将深入探讨Web3如何重塑物联网生态系统,从技术原理到应用实例,全面解析其对未来科技发展的影响和潜力。 1. Web3技术简介与发展背景 Web3技术是建立在…...
C++之模板(二)
1、类模板 2、使用类模板 类模板在使用的时候要显示的调用是哪种类型,而不是像函数模板一样能够根据参数来推导出是哪种类型。 Stack.h #include <stdexcept>template <typename T> class Stack { public:explicit Stack(int maxSize);~Stack();void …...
相机的标定
文章目录 相机的标定标定步骤标定结果影响因素参数分析精度提升一、拍摄棋盘格二、提升标定精度 标定代码实现 相机的标定 双目相机的标定是确保它们能够准确聚焦和成像的关键步骤。以下是详细的标定步骤和可能的结果,同时考虑了不同光照条件和镜头光圈大小等因素对…...
C# 利用XejeN框架源码,编写一个在 Winform 界面上的语法高亮的编辑器,使用 Monaco 编辑器
析锦基于Monaco技术实现的Winform语法高亮编辑器 winform中,我们有时需要高亮显示基于某种语言的语法编辑器。 目前比较强大且UI现代化的,无疑是宇宙最强IDE的兄弟:VS Code。 类似 VS Code 的体验,可以考虑使用 Monaco Editor&a…...
03- jQuery事件处理和动画效果
1. jQuery的事件处理 1.1 绑定事件处理函数 on() 将一个或多个事件的处理方法绑定到被选择的元素上。on()方法适用于当前或未来的元素,如用脚本创建的新元素。 $(selector).on(event,childSelector,data,function) 参数描述event必需。规定要从被选元素添加的一…...
RabbitMQ 入门
目录 一:什么是MQ 二:安装RabbitMQ 三:在Java中如何实现MQ的使用 RabbitMQ的五种消息模型 1.基本消息队列(BasicQueue) 2.工作消息队列(WorkQueue) 3. 发布订阅(Publish、S…...
物联网协议应用
目录 前言一、WIFI简介二、NTP协议2.1 NTP简介2.2 NTP实现 三、HTTP协议3.1 HTTP协议简介3.2 HTTP服务器 四、MQTT协议4.1 MQTT协议简介4.1.1 MQTT通信模型4.1.2 MQTT协议实现原理4.1.3 MQTT 控制报文 4.2 移植MQTT协议 前言 本文主要介绍一下物联网协议如NTP协议、HTTP协议和M…...
十分钟学会微调大语言模型
有同学给我留言说想知道怎么训练自己的大语言模型,让它更贴合自己的业务场景。完整的大语言模型训练成本比较高昂,不是我们业余玩家能搞的,如果我们只是想在某个业务场景或者垂直的方面加强大模型的能力,可以进行微调训练。 本文…...
结合简单工厂和工厂方法模式:实现灵活的对象创建
前言 在软件开发过程中,创建对象的方式直接影响代码的灵活性和可维护性。设计模式提供了一种解决复杂问题的方法,其中简单工厂模式和工厂方法模式是两种常用的创建型模式。在这篇文章中,我们将结合这两种模式,通过一个实际案例&a…...
网抑云特殊版,登录即永久
前言 今天分享一款特殊版本的音乐软件,相信大家在听网抑云的时候会有两大烦恼, 一是歌曲需要开通VIP才可以收听,不管怎么说也是国内厂商普遍操作 但是第二种烦恼你万万想不到的是,开通了会员后,惊奇的发现ÿ…...
Kotlin 实战小记:No-Arg 引用解决 No constructor found的问题
一、问题 新的项目试用一下kotlin, 调用数据库查询数据的时候报了这个问题:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.neusoft.collect.entity.cm.CmRoom matc…...
HTML(5)——列表表格
列表 无序列表 作用:布局排列整齐的不需要规定顺序的区域。 标签:ul嵌套il,ul是无序列表,li是列表条目 注:ul标签只能包裹li标签,li标签可以包含任何内容 有序列表 作用:布局排列整齐的需…...
FreeBSD通过CBSD管理低资源容器jail来安装Ubuntu子系统实践
简介 FreeBSD、CBSD、Jail和Ubuntu,四者的组合方案可以说是强强联合,极具性价比和竞争力!同时安装简单方便,整体方案非常先进。 CBSD是为FreeBSD jail子系统、bhyve、QEMU/NVMM和Xen编写的管理层。该项目定位为一个综合解决方案…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...
