Flask——模板

模板

1-模板的简介

模板是一个web开发必备的模块。因为我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,二手需要渲染一个有富文本标签的页面。这时候我们就需要使用模板了。在Flask中,配套的模板是JinJa2,Jinja2的作者也是Flask的作者。这个模板非常强大,并且执行效率高。

Flask渲染Jinja模块

  • 渲染模板使用的方法为render_template
  • 当使用该模板的时候,该模板会自动的去templates该文件夹目录下寻找该html文件来作为模板
  • 当访问/about/的时候,about()函数会在当前目录下的templates文件夹下寻找index.html模板文件。如果想更改模板文件地址,应该在创建app的时候,给Flask传递一个关键字参数template_foloer指定具体的路径
# -*- coding: utf-8 -*- 
# @Time : 2020/4/9 16:54 
# @Author : 大数据小J

# render_template:渲染模板
from flask import Flask, render_template

app = Flask(__name__)

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


@app.route('/about/')
def about():
    # end
    return render_template('index.html')


if __name__ == '__main__':
    app.run()	
from flask import Flask,render_template
app = Flask(__name__,template_folder=r'C:\templates')

@app.route('/about/')
def about():
    return render_template('about.html')
# -*- coding: utf-8 -*- 
# @Time : 2020/4/9 16:54 
# @Author : 大数据小J

# render_template:渲染模板
from flask import Flask, render_template

app = Flask(__name__)


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


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


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


if __name__ == '__main__':
    app.run(debug=True)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GvH1hVQ9-1586752788779)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409171610239.png)]

模板传参

  • 如果只有一个或者少量参数,直接在render_template函数中添加关键字参数就可以了。
  • 如果有多个参数的时候,那么可以先把所有的参数放在字典中,然后在render_template中,
  • 使用两个星号,把字典转换成关键字参数传递进去,这样的代码更方便管理和使用
  • 在模板中,如果要使用一个变量,语法为{{要打印的参数}}
  • 访问模型中的属性或者字典,可以通过{{params.property}}形式,或则是使用{{params['age']}}
  • **contextrender_template方法中会自动解析以字典形式的数据
# -*- coding: utf-8 -*- 
# @Time : 2020/4/9 17:17 
# @Author : 大数据小J

from flask import Flask, render_template

app = Flask(__name__)


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


@app.route('/about/')
def about():
    # return render_template('index.html', username='SmallJ', study={'Python', 'Java', 'PHP'},
    #                        data={'name': 'SmallJ', 'age': 18, 'class': '三班'})

    context = {
        'username': 'SmallJ',
        'age': 18,
        'study': 'Python'
    }
    # **context相当于会把字典变成对应的关键字的形式
    # username=SmallJ
    return render_template('index.html', **context)


if __name__ == '__main__':
    app.run(debug=True)
	
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
    <h1>{{ username }}</h1>
    {# <h1>{{ study }}</h1>} #}
    <h1>{{ age }}</h1>
    <h1>{{ study }}</h1>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-popgZUn8-1586752722314)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409174716937.png)]

2-Jinja2模板过滤器

Jinja2模板过滤器

过滤器是通过管道符号(|)进行使用的,例如:{{name|length}},将返回name的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中。Jingja2中内置了许多过滤器,在这里可以看到所有的过滤器。

  • abs(value) :返回一个数值的绝对值
  • default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数的值来代替name|defalut('SmallJ')——如果name值不存在,则会使用SmallJ来替换。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用Python的形式判断是否为False,则可以传递boolean=true。也可以使用or来替换
  • escape(value):转义字符
  • first(value):返回一个序列的第一个元素。
  • formate(value,*arags,**kwargs):格式化字符串
  • last(value):返回一个序列的最后一个元素。
  • length(value):返回序列的长度
  • join(value,d='要拼接的字符串'):将一个序列用d这个参数的值拼接成字符串
  • safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义
  • int(value):将值转换成int类型
  • float(value):将值转换为float类型
  • lower(value):将字符串转换成小写
  • upper(value):将字符串转换成大写
  • replace(value,old,new):替换将old替换为new的字符串
  • truncate(value, length=255, killwords=False):截取length长度的字符串
  • striptags(value):删除字符串中的所有的HTML标签,如果出现多给空格,将替换成一个空格。
  • trim:截取字符串前面和后面的空白字符(不包括中间的字符)
  • sring(value):将变量转换成字符串
  • wordcount(s):计算一个字符串中单词的个数(其实是按照空格来进行计算,也可以通过s来指定修改的内容)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NRFxx9f2-1586752722315)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200411004115627.png)]

自定义模板过滤

​ 自定义模板使用的方法为template_filter()括号里面传模板自定义使用的名字,在模板中生效使用

# -*- coding: utf-8 -*- 
# @Time : 2020/4/10 23:45 
# @Author : 大数据小J

# 导入模板文件: render_template

from flask import Flask, render_template

app = Flask(__name__)


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


@app.route('/index/')
def index():
    context = {
        'username': 'SmallJ',
        'age': -18,      # 当我传入一个负数值的时候可以通过Jinja2模板中的abs绝对值来改变,返回项目上线的时候出现负数的形式
        'class': '三班',
        'Javascript': '<script>alert("hello");</script>',
        # first返回第一个元素,当为列表的时候,返回Python。当为字符串的时候返回P
        # last返回元素中最后一个元素值
        'books': ['Python', 'Java', 'PHP'],
        'data': {
            'students': 'SmallJ',
            'id': 9947,
            'number': 'demodemo',
            'Study': 'PHP'
        },
        'height': '174.5',
        'label': '<a href="https://passport.baidu.com/v2/?login" class="account-login">登录</a>',
        'content': '  No problem   ',
        'word_data': '分词结果'
    }
    return render_template('index.html', **context)


# 自定义模板过滤   ()括号中的值为自己在模板中自定义使用的名字
@app.template_filter('my_filter')
# 这里为什么要有个value呢,,就是你需要自己定义一个模板方法,没有value跟直接return没什么区别
def add(value):
    return value.replace('SmallJ', 'SevenJ')


if __name__ == '__main__':
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {#{模板过滤器是通过管道符号(|)来执行的,过滤器相当于是函数,把当前的变量传入到过滤器当中,然后过滤器通过根据自己的功能在返回相应的结果
    abs():为绝对值
    default('要替换的值'):当传入变量的值不存在的时候,模板会选择default中的值来进行
    safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义
    first(value):返回序列中的第一个元素
    last(value):返回一个序列中最后一个元素值
    format(value, *arags, **kwargs):格式化字符串
    length(value):返回一个序列或者字典的长度,长度从1开始
    int(value):返回的结果为整型
    float(value):返回的结果为浮点型
    lower(value):将字符串转换为小写
    upper(value):将字符串转换为大写
    replace(value, old, new):将把ord替换为new的字符串
    striptags(value):删除字符串中所有的HTML标签,如果出现多个空格,将替换成为空格
    trim:截取字符串前面和后面的空白字符(但不会去掉中间的空格)
    string(value):将变量转换成字符串
    wordcount(s):计算一个常字符串中单词的个数(wordcount分词是按照空格的形式来进行分词)
    my_filter:对应着自己自定义的模板名字

    }#}
    <p>{{ username }}</p>
    <p>{{ age|abs() }}</p>
    <p>{{ name|default('SenvenJ') }}</p>
    <p>{{ books|first() }}</p>
    <p>{{ books|last() }}</p>
    <p>{{ "%s"|format('StudyJinja2模板') }}</p>
    <p>{{ books|first()|length() }}</p>
    <p>{{ height|int() }}</p>
    <p>{{ username|lower() }}</p>
    <p>{{ username|upper() }}</p>
    <p>{{ books|first()|replace('ython','YTHON') }}</p>
    <p>{{ label|striptags() }}</p>
    <p>{{ content|trim() }}</p>
    <p>{{ height|string() }}</p>
    <p>{{ word_data|wordcount() }}</p>
    <p>{{ username|my_filter }}</p>



</body>
</html>

显示时间

# -*- coding: utf-8 -*- 
# @Time : 2020/4/11 21:55 
# @Author : 大数据小J
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)


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


# 建立模板文件
@app.route('/index/')
def index():
    context = {
        'username': 'SmallJ',
        'datetime': datetime(2020, 4, 11, 22, 42, 00)
    }
    return render_template('filter.html', **context)


# 自定义模板过滤
@app.template_filter('my_filter')
def add(time):
    """
    大于一分钟:显示刚刚
    大于1分钟小于1小时:xx分钟之前
    大于1小时小于24小时:显示xx小时之前
    :param time:
    :return:
    """
    if isinstance(time, datetime):
        now_time = datetime.now()
        # total_seconds转换成秒数,两个时间戳进行相减
        timestamp = (now_time-time).total_seconds()
        if timestamp < 60:
            return '刚刚'
        elif timestamp >= 60 and timestamp <= 60*60:
            return "{}分钟之前".format(int(timestamp/60))
        elif timestamp >= 60*60 and timestamp<= 24*60*60:
            return '{}小时之前'.format(int(timestamp/(60*24)))
    else:
        return time


if __name__ == '__main__':
    app.run(debug=True, port=8888)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{ username }}</h1>
    <h1>{{ datetime|my_filter }}</h1>
</body>
</html>	

3-控制语句

​ 所有的控制语句都是放在{ %…% }中,并且有一个语句{ % endxxx %}来进行结束,Jinja中常用的控制语句有if for in

for...in...:for循环可以遍历任何一个序列包括列表、字典、元组。并且可以进行反向遍历

# -*- coding: utf-8 -*- 
# @Time : 2020/4/13 9:07 
# @Author : 大数据小J

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World'


@app.route('/decide/')
def decide():
    context = {
        'username': 'SmallJ',
        'study': ['Python', 'PHP', 'Java'],
        'data': {
            'username': 'SmallJ',
            'age': 18,
            'city': '广州'
        }
    }
    return render_template('if_for.html', **context)


if __name__ == '__main__':
    app.run(debug=True)

 

并且Jinja中的for循环还包括以下变量,可以用来获取当前的遍历状态。

loop.index:返回当前索引(从1开始)。

loop.first:判断当前是否是第一次迭代,返回 True 或者 False。

loop.last:判断当前是否为最后一次迭代,返回True 或者 False。

loop,length:返回序列的长度

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
{# {hr为分割线
    li为无序标点
    loop.index:返回当前迭代的索引(从1开始)
    loop.first:判断当前是否第一次迭代,返回True 或者 False
    loop.last: 判断当前是否是最后一次迭代,返回True 或者 False
    loop.length:返回序列的长度
} #}
<body>

{% if username == 'SmallJ' %}
    <p>这是SmallJ</p>
{% else %}
    <p>这不是SmallJ</p>
{% endif %}

{% for book in study %}
    <li>{{ loop.last }}</li>
    <li>{{ loop.index}}</li>
    <li>{{ book }}</li>
{% endfor %}

{% for key, value in data.items() %}
<hr>
    <p>{{ loop.first}}</p>
    <p>{{ loop.length }}</p>
    <p>{{ key }}</p>
    <p>{{ value }}</p>
{% endfor %}
<hr>
</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plXOgXjE-1586752722316)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200413095800663.png)]

4-宏和input

​ 模板中的宏跟Python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% macro input(name, value='', type='text') %}
        <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
    <p>用户名: {{ input('username') }}</p>
    <p>密码: {{ input('password', type='password') }}</p>
    <p>{{ input(value='提交',type='submit') }}</p>
</body>
</html>	
# -*- coding: utf-8 -*- 
# @Time : 2020/4/13 11:01 
# @Author : 大数据小J
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello_world():
    return '欢迎来到Flask世界'


@app.route('/sud/')
def sud():
    context = {
        'username': 'SmallJ'
    }
    return render_template('macro.html', **context)


if __name__ == '__main__':
    app.run(debug=True)	

import语句

​ 在真实的开发中,会将一些常用的宏单独放在一个文件中,在需要使用的时候,再从这个文件中进行导入。import语句的用法跟Python中的import类似,

  • 导入方式一:import ‘导入的html’ as 重命名

  • 导入方式二:import '导入的宏html' import 导入的模块

    另外需要注意的是,导入的模块并不会把当前上下文的变量添加到被导入的模板中,如果你想要导入一个需要访问当前上下文变量的宏,有两种可能的方法。

    • 显示地传入请求或请求对象的属性作为宏的参数
    • 与上下文一起(with context)导入宏

    macro.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% macro input(name, value='', type='text') %}
        <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
<!--    <p>用户名: {{ input('username') }}</p>-->
<!--    <p>密码: {{ input('password', type='password') }}</p>-->
<!--    <p>{{ input(value='提交',type='submit') }}</p>-->
</body>
</html>

导入宏文件macro_copy.html

{% import 'macro.html' as macro %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>用户名: {{ macro.input('username') }}</p>
    <p>密码: {{ macro.input('password', type='password') }}</p>
    <p>{{ macro.input(value='提交', type='submit') }}</p>
</body>
</html>
# -*- coding: utf-8 -*- 
# @Time : 2020/4/13 11:01 
# @Author : 大数据小J
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello_world():
    return '欢迎来到Flask世界'


@app.route('/sud/')
def sud():
    context = {
        'username': 'SmallJ'
    }
    return render_template('macro_copy.html', **context)


if __name__ == '__main__':
    app.run(debug=True)

在这里插入图片描述

5-include和set语句

inclde语句

include语句可以把一个模板引入到另外一个模板中,类似于把一个模板的代码copy到另外一个模板的指定位置

inclde的好处

  • 代码复用性高
  • 节省项目的开发时间

title.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p1>国内</p1>
    <p1>国外</p1>
    <p1>国际</p1>
    <p1>军事</p1>
    <p1>财经</p1>
    <p1>娱乐</p1>
    <p1>体育</p1>
    <p1>互联网</p1>
</body>
</html>	

botton.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p1>百度新闻独家作品</p1>
    <p1>1. 新闻由机器选取每5分钟自动更新</p1>
    <p1>2. 百度新闻搜索源于互联网新闻网站和频道,系统自动分类排序</p1>
    <p1>3. 百度不刊登或转载任何完整的新闻内容</p1>
</body>
</html>

personal.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# {common为templates文件夹目录下的文件夹} #}
    {% include 'common/title.html' %}
    <p>这是中心内容</p>
    {% include 'common/botton.html' %}
</body>
</html>
# -*- coding: utf-8 -*- 
# @Time : 2020/4/13 11:59 
# @Author : 大数据小J

from flask import Flask, render_template

app = Flask(__name__)


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


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


if __name__ == '__main__':
    app.run(debug=True)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-anw23OLc-1586753104804)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200413121321029.png)]

赋值(set)语句

有时候我们想在模板中添加变量,这很好赋值语句(set)就派上用场了{% set name='SmallJ' %}

当定义了set语句的时候,该值为全局变量的值,当代码和模板中同时出现name值的时候,模板中的name值高于代码中name的值

赋值语句创建的变量在其之后都是有效的,如果不想让一个变量渲染全局环境,可以使用with语句来创建语句一个内部的作用域,将set语句放在其中,这样创建的变量只在with代码中才有效。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# {set为全局变量} #}
    {# {当我们想让set为局部变量的时候我们可以通过with 和 endwith 代码块中实现 } #}
    {% set username='SmallJ' %}
    {% include 'common/title.html' %}
    <p>这是中心内容</p>
    <p>{{ username}}</p>
    <hr>
    {% with %}
        {% set name='这是局部的' %}
        <h1>{{ name }}</h1>
    {% endwith %}
    {% include 'common/botton.html' %}
</body>
</html>
# -*- coding: utf-8 -*- 
# @Time : 2020/4/13 11:59 
# @Author : 大数据小J

from flask import Flask, render_template

app = Flask(__name__)


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


@app.route('/filter/')
def filter():
    context = {
        'username': '大数据小J'
    }
    return render_template('personal.html', **context)


if __name__ == '__main__':
    app.run(debug=True)

在这里插入图片描述

6-模板继承

为什么需要模板继承

​ 模板继承可以把一些公用代码单独抽取出来放到一个父模板中,以后子模板直接继承就可以使用。这样重复的代码修改起来也会比较方便

模板继承的语法

使用{% extend '要继承的模板html' %}

block语法

​ 一般在父模板中,定义一些公共的代码。子模板可能要根据具体的需求实现不同的代码。

​ 这时候父模板就应该提供一个接口,让父模板来实现。从而实现具体业务需求的功能

在父模板中定义:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% block content %}
            <li>国内</li>
            <li>国外</li>
            <li>军事</li>
            <li>科技</li>
            <li>生物</li>
            <li>生活</li>
        {% endblock %}

    </ul>
    {% block title %}
     <h1>这是父模板中的首页</h1>
    {% endblock %}
    {% block footer %}
        <div class="footer">
        这是文章的底部内容
        </div>
    {% endblock %}


</body>
</html>

succde.html

{# {extends 中文意思为扩展} #}
{% extends 'index.html' %}

{% block title %}
    <h1>这是子模板中的首页</h1>
{% endblock %}

调用父模板的代码block中的代码

​ 默认情况下,子模板如果实现了父模板定义的block,那么子模板block中的代码就会覆盖掉父模板中的代码,如果想在子模板中仍然保持父模板代码,需要用{{ super() }}函数调用

{# {extends 中文意思为扩展} #}
{% extends 'index.html' %}

{% block title %}
    {{ super() }}
    <h1>这是子模板中的首页</h1>
{% endblock %}

总结

  • 子模板中的代码,第一行应该是继承的代码{% extends '要继承的父模板.html' %}

  • 子模板中,如果要实现自己的代码,应该放在block里面,如果放在外码,将无法被渲染

  • 当子模板继承了父模板后,没有对父模板进行block修改的时候,默认情况下会全部继承子模板。

  • block名字不能够重名,block可以嵌套

  • 在子模板中不能自己定义标签,但可以在父模板中定义标签。

静态文件的配置

​ 静态资源文件一般会放在flask项目下的static文件目录下面。Web应用中会出现大量的静态文件来使得网页更加生动美观。类似于css样式文件、JavaScript脚本文件、图片文件、字体文件等静态资源。在Jinja中加载静态文件非常简单,只需要通过url_for全局函数就可以实现了。

​ 静态资源文件使用的是<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">

  • 静态资源文件使用的是url_for,第一个值默认为static为样式文件,``filename`:为加载样式文件的目录
  • 默认请求下,静态资源文件会去static文件下找相对应的文件
  • JavaScrip和imags同理。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
    <img src="{{ url_for('static',filename='images/index.png')}}" alt="">
</head>
<body>
    <ul>
        {% block content %}
            <li>国内</li>
            <li>国外</li>
            <li>军事</li>
            <li>科技</li>
            <li>生物</li>
            <li>生活</li>
        {% endblock %}

    </ul>
    {% block title %}
     <h1>这是父模板中的首页</h1>
    {% endblock %}
    {% block footer %}
        <div class="footer">
        这是文章的底部内容
        </div>
    {% endblock %}


</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值