FLASK学习杂记(三)Flask模板

  • 一、Flask模板使用
    • 1.render_template()
    • 2.静态文件
    • 3.修改模板位置
  • 二、模板传参
    • 1.关键字传参
    • 2.封装字典传参
    • 3.**字典传参
    • 4.列表、元组、字典取用
  • 三、模板基础
    • 1.Jinja分隔符配置
    • 2.模板过滤器
      • 内置过滤器
      • 自定义过滤器
    • 3.结构控制
      • for循环
      • 条件语句
      • 块和模板继承
      • set
    • 4.Jinjia表达式

一、Flask模板使用

函数返回一段前端代码,会被flask自动解析,在前端中展示。

@app.route('/index')
def index():
    return '<h6>请输入:</h6><input name="inp">'

但直接返回html代码,不利于前后端分离,flask为此提供了Jinja2模板引擎,可以通过render_template()方法渲染模板,再返回给前端。

1.render_template()

写一个简单的html文件

<!DOCTYPE html>
<html lang="en">
	<head>
	    <meta charset="UTF-8">
	    <title>index</title>
	</head>
	<body>
		<h6>请输入:</h6>
		<input name="inp">
	</body>
</html>

用render_template()渲染,flask会在templates文件夹内找到要渲染的html文件。

from flask import render_template

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

2.静态文件

在前端开发过程中,也需要css、js 静态文件,flask提供了一个static的文件夹,用于存储相关静态文件。
在static问价夹下新建一个css文件夹用于存储css文件,同理也可在此新建一个js文件夹,用于存储js文件。

这里可以用到url_for()来获取文件地址

<!DOCTYPE html>
<html lang="en">
	<head>
	    <meta charset="UTF-8">
	    <title>index</title>
	    <link rel="stylesheet" href="{ { url_for('static',filename='css/index.css') }}">
	</head>
	<body>
		<h6>请输入:</h6>
		<input name="inp">
	</body>
</html>

css修改h6标签颜色

h6{ 
    color: aquamarine;
}

如果想修改静态文件默认位置,可以在flask初始化时候设置static_folder

from flask import Flask
app = Flask(__name__,static_folder='staticfiles')

3.修改模板位置

如果想要自定义模板存放位置,可以在初始化flask的时候,设置template_folder

from flask import Flask
app = Flask(__name__,template_folder='./static/templates')

二、模板传参

render_template(template_name_or_list,**context) 中第一个参数为要渲染的模板或带有模板名称的迭代器,但指挥渲染第一个,第二个参数即为要传给前端的参数。

1.关键字传参

@app.route('/')
def hello_world():
    return render_template('index.html',username='Tom',password='123456')

对于username等,前端可以通过{ { username }}的形式直接使用。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h1>{
  { username }}</h1>
        <h2>{
  { password }}</h2>
    </body>
</html>

2.封装字典传参

@app.route('/')
def hello_world():
    dic = { 
        'username':'Tony',
        'password':'123456z'
    }
    return render_template('index.html',dic = dic)

将所有要穿的参数封装成一个字典传dic给前端,前端可以通过{ {dic.username}}或{ {dic[‘username’]}}的形式取到

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h1>{
  { dic.username }}</h1>
        <h2>{
  { dic['password'] }}</h2>
    </body>
</html>

3.**字典传参

首先将所有变量封装成字典,然后通过**传递。

@app.route('/')
def hello_world():
    context = { 
        'username':'Tony',
        'password':'123456z',
        'score':{ 
            'Chinese':89,
            'math':96,
            'PE':70
    	}
    }
    return render_template('index.html',**context)

与封装成字典传参不同的是,**context传参前端可以直接通过所需参数名获取

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h1>{
  { username }}</h1>
        <h2>{
  { password }}</h2>
        <h3>{
  { score.Chinese }}</h3>
        <h3>{
  { score.math }}</h3>
        <h3>{
  { score['PE'] }}</h3>
    </body>
</html>

4.列表、元组、字典取用

@app.route('/')
def hello_world():
    dic = { 
        'username':'Tony',
        'password':'123456z'
    }
    li = ['Jack','Tom']
    tup =(1,3,5)
    return render_template('index.html',li = li,tup=tup,dic = dic)
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h1>{
  { li.0 }}</h1>
        <h1>{
  { li[1] }}</h1>
        <h2>{
  { tup.0 }}</h2>
        <h2>{
  { tup[2] }}</h2>
        <h3>{
  { dic.username }}</h3>
        <h3>{
  { dic['password'] }}</h3>
    </body>
</html>

三、模板基础

Flask采用Jinja2模板引擎,Jinja模板语法受Django和Python启发,有Python和Django基础更容易理解。

1.Jinja分隔符配置

  • {% … %}用于声明,如:{% for i in sep -%}
  • { { … }} 用于打印,如:{ { i }}
  • {# … #} 用于注释,类似<!– 这是注释 –>
  • # … ## 行语句
@app.route('/')
def hello_world():
    li = ['Jack','Tom','Kitty']
    return render_template('index.html',li = li)
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h1>
            {% for item in li%}
                {# 这里是注释的内容 #}
                {
  { item }}
            {% endfor %}
        </h1>
    </body>
</html>

2.模板过滤器

内置过滤器

abs绝对值

@app.route('/')
def hello_world():
    li = [1,-2,3,-4]
    return render_template('index.html',li = li)
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h2>
            {% for item in li %}
                {
  { item|abs }}
            {% endfor %}
         </h2>
    </body>
</html>

capitalize首字母大写

@app.route('/')
def hello_world():
    li = ['tom','kitty','sindy','jack']
    return render_template('index.html',li = li)
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h2>
            {% for item in li %}
                {
  { item|capitalize }}
            {% endfor %}
        </h2>
    </body>
</html>

default
如果传入的变量为空,会打印定义好的文字,如果不为空要打印变量,需要设置boolean=true。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h2>
            {
  { is_null|default('this varity is not defined') }}
            <br>
            {
  { "--"|default('this varity is not defined',boolean=true) }}
        </h2>
    </body>
</html>

dictsirt字典排序
dictsort可以按键或值对字典进行排序,用关键字by来控制,用reverse=true来控制升序,默认false,降序。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h2>
            原数据:
            <br>
            {
  { mydict }}
            <br>
            按键排序:
            <br>
            {% for item in mydict|dictsort(by ='key') %}
                {
  { item }}
            {%  endfor %}
            <br>
            按值排序 降序:
            <br>
            {% for item in mydict|dictsort(by ='value') %}
                {
  { item }}
            {%  endfor %}
            <br>
            按值排序 升序:
            <br>
            {% for item in mydict|dictsort(by ='value',reverse=true) %}
                {
  { item }}
            {%  endfor %}
            <br>
            {
  { mydict }}

        </h2>
    </body>
</html>

可以看到dictsort排序不会对原数据进行修改。

escape转义
在字符串中,如果存在&,<,>等,需要转义成普通字符,才能避免被渲染成html元素,然在flask中会自动将这些字符转义成普通字符。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {
  { '<h1>你好!;&nbsp北京。</h1>' }}
        </h3>
        <h2>
            {
  { '<h1>你好!;&nbsp北京。</h1>'|e }}
        </h2>
        <h1>
            {
  { '<h1>你好!;&nbsp北京。</h1>'|escape }}
        </h1>
    </body>
</html>

first、last、length
first返回元素第一项目,last返回最后一个元素,length返回元素长度

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {
  { 'hello'|first }}
        </h3>
        <h2>
            {
  { 'hello'|last }}
        </h2>
        <h1>
            {
  { 'hello'|length }}
        </h1>
    </body>
</html>

join
将序列中的元素串联成字符串,默认串联符为空格。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {
  { [1,2,3,4,5]|join }}
        </h3>
        <h2>
            {
  { [1,2,3,4,5]|join(',') }}
        </h2>
        <h1>
            {
  { [1,2,3,4,5]|join('->') }}
        </h1>
    </body>
</html>

replace
替换元素中字符为另一个字符

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {
  { 'everyday,everynight'|replace('every','no') }}
        </h3>
    </body>
</html>

其他过滤器
其他过滤器在此不做详细阐述,可以参考jinja官网上内置过滤器列表查看所有jinja过滤器。

自定义过滤器

通过装饰器template_filter()可以在后端自定义过滤器。

@app.template_filter('my_replace')
def rep(value):
    return value.replace('.','!')
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {
  { 'everyday,everynight.' }}
        </h3>
        <h3>
            {
  { 'everyday,everynight.'|my_replace }}
        </h3>

    </body>
</html>

3.结构控制

结构控制包括for循环、if/elif/else条件语句、宏以及块,用{% …%}来控制,每个控制语句要有对应的{% end… %}来结束。

for循环

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {% for item in ['Tom','Jack','Tony'] %}
                {
  { item }}
            {% endfor %}
        </h3>
    </body>
</html>

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {% for item in [] %}
                {
  { item }}
            {%  else %}
                did not iterate
            {% endfor %}
        </h3>
    </body>
</html>

如上,用{% endfor %} 来结束循环。

for-loop特殊变量访问
loop.index

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {% for item in ['Tom','Jack','Tony'] %}
                {# 从1开始的迭代 #}
                {
  { loop.index }}:{
  { item }}
                <br>
            {% endfor %}
        </h3>
    </body>
</html>

loop.index0

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 从0开始的迭代 #}
        {
  { loop.index0 }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.revindex

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 从item.length到1的迭代 #}
        {
  { loop.revindex }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.revindex0

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 从item.length-1到0的迭代 #}
        {
  { loop.revindex0 }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.first

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 是否为第一次迭代,返回布尔值 #}
        {
  { loop.first }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.last

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 是否为最后一次迭代,返回布尔值 #}
        {
  { loop.last }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.length

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 返回元素数目 #}
        {
  { loop.length }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.cycle

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 在指定元素中循环产生索引 #}
        {
  { loop.cycle('a','b') }}:{
  { item }}
        {
  { loop.cycle('a','b','c','d') }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.depth、loop.depth0

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 迭代深度,从1开始 #}
        {
  { loop.depth }}:{
  { item }}
         <br>
        {# 迭代深度,从0开始 #}
        {
  { loop.depth0 }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.previtem

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 查看元素的前一个元素 #}
        {
  { loop.previtem }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

loop.nextitem

<h3>
    {% for item in ['Tom','Jack','Tony'] %}
        {# 查看元素的后一个元素 #}
        {
  { loop.nextitem }}:{
  { item }}
        <br>
    {% endfor %}
</h3>

条件语句

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
        <h3>
            {% for item in ['about','boy','kill'] %}
                {
  { item }}
                {% if item|first =='a' %}
                    该字母以a开头
                {%  elif item|first == 'b' %}
                    该字母以b开头
                {%  else %}
                    该字母不以a、b开头
                {%  endif %}
                <br>
            {% endfor %}
        </h3>
    </body>
</html>

可以将宏理解为函数,复用功能,以避免代码重复,可以传参但没有返回值。
用{% macro name(parameter1,parameter2,…) %}的形式来定义宏,parameter为参数,可以设置默认值。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    {% macro input(name,value='',type='text',size=20) %}
        <input type="{
  { type }}" name="{
  { name }}",value="{
  { value|e }}",size="{
  { size }}">
    {% endmacro %}

    <p>用户名:{
  { input('username') }}</p>
    <p>&nbsp;&nbsp;&nbsp;码:{
  { input('password',type='password') }}</p>
    <p>{
  { input('提交',type='submit') }}</p>
    </body>
</html>

import宏
在世纪开发中,会把宏放入一个单独的html文件中,在使用的时候需要导入
macro.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>macro</title>
</head>
<body>
{% macro input(name,value='',type='text',size=20) %}
        <input type="{
  { type }}" name="{
  { name }}",value="{
  { value|e }}",size="{
  { size }}">
{% endmacro %}
</body>
</html>

index.html
import

{% import 'macro.html' as marco %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <p>用户名:{
  { marco.input('username') }}</p>
    <p>&nbsp;&nbsp;&nbsp;码:{
  { marco.input('password',type='password') }}</p>
    <p>{
  { marco.input('提交',type='submit') }}</p>
    </body>
</html>

from … import …

{% from 'macro.html' import input  %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <p>用户名:{
  { input('username') }}</p>
    <p>&nbsp;&nbsp;&nbsp;码:{
  { input('password',type='password') }}</p>
    <p>{
  { input('提交',type='submit') }}</p>
    </body>
</html>

块和模板继承

块的存在为jinjia模板继承提供了很大的便利,用{% block name %}来定义,每个块结束都由对应的{% endblock %} 来控制,也可用{% endblock name %} 来结束以增加可读性。

*{ 
    margin: 0;
    padding: 0;
}

.bg{ 
    width: 1500px;
    height: 50px;
    background-color: #e7b434;
}

#top{ 
     background-color: antiquewhite;
}

#footer{ 
    background-color: #6d6a6a;
}

父模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {%  block title%}
        base
        {%  endblock %}
    </title>
    <link rel="stylesheet" href="{ { url_for('static',filename='css/base.css') }}">
</head>
<body>

<div id="top" class="bg">
</div>
<div class="bg">
    {% block center %}
    <h1>这里是要被继承的父模块</h1>
    {% endblock %}
</div>
<div id="footer" class="bg"></div>
</body>
</html>
@app.route('/block/')
def block():
    return render_template('base.html')

子模块

{% extends 'base.html' %}

{% block title %}
extend
{% endblock %}

{% block center %}
<h2>这是继承了父模板的子模板</h2>
{% endblock %}
@app.route('/extendblock/')
def extendblock():
    return render_template('extend.html')

可以看到子模块中只需要修改被block包裹的部分即可。
用super()调用父块结果:

{% extends 'base.html' %}

{% block title %}
extend
{% endblock %}

{% block center %}
<h2>这是继承了父模板的子模板</h2>
    {
  { super() }}
{% endblock %}

可以看到父块的结果被返回。
嵌套扩展

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

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

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

parent

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}
        Parent
        {% endblock %}
    </title>
</head>
<body>
body: {% block body %}This is from parent.{% endblock %}
</body>
</html>

child

{% extends 'parent.html' %}
{% block title %}Child
{% endblock%}

{% block body %} This is Child. {
  { super() }}
{% endblock %}

grandchild

{% extends 'child.html' %}
{% block title %} Grandchild{% endblock %}
{% block body %}This is grandchild.
{
  { super.super() }}
{% endblock %}

parent

child

grandchild
用super.super()可以引用parent。

set

可以理解成定义变量并赋值,有作用域限制,在块内设置的变量无法现实在块外,循环中设置的也无法显示在循环外。如下,在循环内外set一个相同的item,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>set</title>
</head>
<body>
{% set item = 0 %}
{% for i in [1,2,3] %}
    i = {
  { i }}
    {% set item = i %}
    item = {
  { item }}
    <br>
{% endfor %}
{% if item == 0%} item {% endif %}
</body>
</html>

如果想实现跨作用域传播,可以通过namespace的方法。
如下,通过namespace() set n.flage = false,n.s=1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>set</title>
</head>
<body>
{% set n = namespace(flage=false,s=1) %}
{% for item in [1,2,3,4] %}
    {
  { item }}
    {% if item > 3%}
        {% set n.flage = true %}
        {% set n.s = item %}
    {% endif %}
    <br>
{% endfor %}
n.flage:{
  { n.flage }},n.s:{
  { n.s }}
</body>
</html>

4.Jinjia表达式

Jinjia表达式与python非常相似,有python基础的更好理解,这里只稍微列举,详细请见Jinjia官网

  • 元组:(’a’,‘b’,‘c’);
  • 列表:[1,2,3] ;
  • 字典:{“user”:“Tom”,“password”:123456}
  • 数学运算 : +(加)、-(减)、*(乘)、%(除)、**(幂)…
  • 比较:== 、!=、>、<、<=、>=
  • 逻辑:and 、 or 、not 、expr
  • 其他:in 、is…

本文地址:https://blog.csdn.net/m0_46221758/article/details/112309593