1.jinja2模板介绍和查找路径

from flask import Flask, render_template
import os

# 之前提到过在渲染模板的时候,默认会从项目根目录下的templates目录下查找模板
# 如果不想把模板文件放在templates文件夹下,那么可以在Flask初始化的时候指定
'''
Flask类的构造函数

    def __init__(
        self,
        import_name,
        static_url_path=None,
        static_folder='static',
        static_host=None,
        host_matching=False,
        subdomain_matching=False,
        template_folder='satori',
        instance_path=None,
        instance_relative_config=False,
        root_path=None
    ):
可以看到有一个template_folder='satori'
我们在初始化的时候可以重新指定
'''
BASE_DIR = os.path.dirname(__file__)
app = Flask(__name__, template_folder=os.path.join(BASE_DIR, "satori"))

@app.route(r"/satori")
def satori():
    return render_template("1.html")

if __name__ == '__main__':
    app.run(host="localhost", port=7777)

  

 

2.模板传参以及技巧

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>my name is {{name}}, age is {{age}}</h1>
</body>
</html>

  

from flask import Flask, render_template
app = Flask(__name__)

@app.route(r"/index")
def index():
    '''
    在html文件中,以{{}}定义,比如{{name}},然后在渲染模板的时候传参进去即可
    通过name="xxx"的形式,会自动进行替换。
    渲染的流程是先把html文件读取进来,再将{{}}里面的内容替换掉,因此最终返回给浏览器的内容是不包含{{}}的
    '''
    return render_template("1.html", name="satori", age=17)

if __name__ == "__main__":
    app.run(host="localhost", port=8888)

  

@app.route(r"/index")
def index():
    '''
    但是如果要替换的内容比较多的话,那么一个一个写的话,风格不是很pythonic
    因此我们会把内容都写在一个字典里,然后通过**传值
    '''
    replace_content = {"name": "mashiro", "age": 16}
    return render_template("1.html", **replace_content)

  

依旧可以打印出结果

既然如此的话,那么我们可不可以传入一个字典或者列表呢呢?然后按照key或者索引的方式呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--可以使用Python的语法d["xx"], 也可以使用d.xx-->
    <h2>my name is {{info['name']}}, age is {{info.age}}</h2>
    <h2>在{{arr}}中,数字1总共出现了{{arr.count(1)}}次</h2>
    <h2>另外两个花括号之间必须要写值,不能是空的花括号,否则报错</h2>
    <h2>但如果两个花括号中间的内容,我们在模板渲染的时候没有传值呢,那么不会显示,也不会报错</h2>
    <h2>比如下面的类容就不会显示,因为在render_template中没有mmp="xx"</h2>
    <h2>{{mmp}}</h2>

</body>
</html>

  

from flask import Flask, render_template
app = Flask(__name__)

@app.route(r"/index")
def index():
    '''
    但是如果要替换的内容比较多的话,那么一个一个写的话,风格不是很pythonic
    因此我们会把内容都写在一个字典里,然后通过**传值
    '''
    info = {"name": "matsuri", "age": 400}
    arr = [1, 1, 2, 3, 1, 1, 3]
    return render_template("1.html", info=info, arr=arr)

if __name__ == "__main__":
    app.run(host="localhost", port=8888)

3.模板中使用url_for的两种方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2><a href="{{link}}">你想成为女装大佬吗?想搞基吗?想的话,就点击进入新世界的大门吧</a></h2>
</body>
</html>

  

from flask import Flask, render_template, url_for
app = Flask(__name__)

@app.route(r"/bili")
def bili():
    import requests
    content = requests.get("http://www.bilibili.com")
    content.encoding = content.apparent_encoding
    return content.text

@app.route(r"/gay")
def gay():
    return render_template("bilibili.html", link=url_for("bili"))

if __name__ == "__main__":
    app.run(host="localhost", port=8888)

  

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2><a href="{{ url_for('bili') }}">你想成为女装大佬吗?想搞基吗?想的话,就点击进入新世界的大门吧</a></h2>
</body>
</html>

  

from flask import Flask, render_template, url_for
app = Flask(__name__)

@app.route(r"/bili")
def bili():
    import requests
    content = requests.get("http://www.bilibili.com")
    content.encoding = content.apparent_encoding
    return content.text

@app.route(r"/gay")
def gay():
    # 替换之后,这里就不用传参了,因为在模板中可以直接获取链接
    return render_template("bilibili.html")

if __name__ == "__main__":
    app.run(host="localhost", port=8888)

  同样的结果

4.jinja2模板过滤器的基本使用

过滤器是通过管道符号|,来进行使用的,例如:{{name|length}},将返回name的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能再返回相应的值,之后再将结果渲染到页面中。jinja2内置了许多过滤器,下面来介绍一个常用的过滤器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{age|abs}}</h1>
</body>
</html>
@app.route(r"/filter")
def foo():
    # 这里传入一个负值
    return render_template("filter.html", age=-18)

  

5.default过滤器详解

之前我们说过,如果我们定义了一个{{mmp}},但是我们在视图函数的render_template中并没有传值,那么{{mmp}}在页面上是不会显示的,当然也不会报错。但是我们想,对于那些没有传值的变量,我们能不能给一个默认值呢?显然是可以的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>{{s1|default("这个人很懒,什么也没留下")}}</h2>
    <h2>{{s2|default("这个人很懒,什么也没留下")}}</h2>
</body>
</html>
@app.route(r"/signature")
def info():
    s1 = "一个人只要好好活着,就足以拯救某个人"
    return render_template("defualt.html", s1=s1)

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>{{s1}}</h2>
    <!--不过这里还有一个问题,那么如果我指定了s2=None,那么页面上就会显示None
        default是否执行,不在于你传的什么值,而在于你有没有传值,只要传了,就不会显示default的内容
        那如果我想,当传入空字符串,空字典等等,在Python中为False的值,还是执行default的内容,
        该怎么办呢?可以加入一个参数boolean=True,表示在Python中bool为False的值也会被包含在内-->
    <h2>{{s2|default("这个人很懒,什么也没留下", boolean=True)}}</h2>
    <!--如果s3为False,那么会自动选择"默认值",两种方式比较类似-->
    <h2>{{s3 or "默认值"}}</h2>
</body>
</html>

  

6.常用过滤器

escape:转义,默认是开启的。{{xxx|escape}}
那么如何关闭转义呢?这里要介绍一下{{}}和{% %},{{}}存放变量,{%%}执行逻辑
{% autoescape off %}
这里的标签是不会被转义的
{% endautoescape %}
safe:和escape相反,意思是安全的。{xxx|safe}也不会被转义
first:{xx|first},返回序列xx的第一个元素,我们也可以直接使用{{xx[0]}}
last:返回最后一个元素
length:返回序列的长度,sum:返回序列的总和
join:{xx|join(sep)},使用sep将序列xx拼接成一个字符串
int:转化为int
float:转化为float
string:转化为str
lower:小写
upper:大写
replace:{xx|replace(old, new)},将xx中old替换成new
truncate:{xx|truncate(length=14)},表示不管你输入多少字符,在页面上最多显示14和,剩下的用几个省略号表示
wordcounts:计算一个长字符串中某单词出现的次数

  

7.自定义过滤器

之前说过过滤器本质上就是个函数,因此我们只需要写个函数,定义相应的逻辑,然后把函数注册到jinja2过滤器当中即可 

我们手动实现以下replace过滤器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>{{s|屮艸芔茻}}</h2>
</body>
</html>

  

@app.route(r"/index")
def index():
    s = "hello satori"
    return render_template("default.html", s=s)
# 仅仅是这样是不起作用的,我们必须要将函数注册到jinja2过滤器当中
@app.template_filter(name="屮艸芔茻")  # 这里的name就是我们在html中使用的过滤器的名字
def cut_hello(string):
    return string.replace("hello", "")

  

8.自定义过滤器处理时间

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>hello 大家好 我是lex,,发表时间:{{time| handle_time}}</p>
</body>
</html>

  

@app.route(r"/status")
def publish():
    import datetime
    time = datetime.datetime(2018, 9, 24)
    return render_template("status.html", time=time)

@app.template_filter(name="handle_time")
def handle_time(time):
    from datetime import datetime
    if isinstance(time, datetime):
        now = datetime.now()
        # 更精确的话可以使用秒
        days = (now - time).days
        if days < 1:
            return "今天"
        elif days < 3:
            return "三天内"
        elif days < 7:
            return "一星期内"
        elif days < 30:
            return "一个月内"
        else:
            return "时间很久远了"
    else:
        # 返回的不是时间格式
        return time

  

9.if语句

和Python中的if语句类似,使用{%%}包裹,但是不要忘记结尾的{%endif%}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% if gender == "f" %}
        <!--这里相当于Python的两层if循环-->
        {% if age >= 18 %}
        <h2>获取我们可以来一场交易</h2>
        {% else %}
        <h2>虽然担些风险但也值得一试</h2>
        {% endif %}
    {%else%}
        {% if age >= 18 %}
        <h2>我不搞基</h2>
        {% else %}
        <h2>可爱的男孩子也是可以的</h2>
        {% endif %}
    {%endif%}
</body>
</html>

  

@app.route(r"/deal")
def deal():
    return render_template("if.html", gender="f", age=16)

  

10.for语句

和Python里面for循环也基本一致,也别忘了结尾的{% endfor %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% for age in ages %}
        <h2>{{age}}</h2>
    {% endfor %}

    <table border="1px solid red">
        <thead>
            <tr>
                <th>姓名</th>
                <th>出场动漫</th>
            </tr>
        </thead>
        <tbody>
            {% for name in girls %}
            <tr>
                <td>{{name}}</td>
                <td>{{girls[name]}}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

  

@app.route(r"/for")
def loop():
    ages = [17, 400, 20, 16, 14]
    girls = {"古明地觉": "东方地灵殿", "四方茉莉": "sola", "牧濑红莉栖": "命运石之门",
             "坂上智代": "Clannad", "神尾观铃": "air"}
    return render_template("for.html", ages=ages, girls=girls)

  

如果想反向遍历,只需要加上一个过滤器,xx|reverse,表示反向遍历xx

此外,jinja2还提供了索引

loop.index   当前迭代的索引(从1开始)

loop.index0  当前迭代的索引(从0开始)

loop.first  是否是第一次迭代,返回True或者False

loop.last  是否是最后一次迭代,返回True或者False

loop.length    序列的长度

我们对刚才的例子做一下修改

11.九九乘法表

在jinja2中,还可以使用range,接下来便实现一个九九乘法表

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table border="1px">
        {% for i in range(1, 10) %}
        <tr>
            <!--此外还有一种方式,那就是jinja2中,for循环是可以带条件的,这句话还可以这么改-->
            <!--{#  {% for j in range(1, 10) if j < i %}, j也从1遍历到10,但必须满足j < i  #}-->
            <!--关于上面的{# #}在jinja中表示注释,html的注释没用,还是会被解释,必须要在模板语言两端加上{# #} -->
            {% for j in range(1, i) %}
                <td>{{j}} * {{i}} = {{i * j}}</td>
            {% endfor %}
        </tr>
        {% endfor %}
    </table>
</body>
</html>

  

@app.route(r"/nine9c法b")
def minus():
    return render_template("九九乘法表.html")

  

12.宏的概念和基本使用

宏,说的通俗一点,就类似于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 %}
    <!--input就类似于函数名,这里叫什么无所谓。name是我们需要传的参数,value和type是缺省参数-->
    <!--当我们执行{#    {{input("satori", "love")}}    #}的时候,等价于<input type="text" name="satori" value="love"/>-->
    <form action="/show" method="post">
        {{input("satori","东方地灵殿")}}
        {{input("mashiro","樱花庄的宠物女孩")}}
        {{input("", "提交", "submit")}}
    </form>
</body>
</html>

  

from flask import Flask, render_template, request
app = Flask(__name__)

@app.route(r"/index")
def index():
    return render_template("1.html")

@app.route(r"/show", methods=["POST"])
def show():
    satori = request.form.get("satori")
    mashiro = request.form.get("mashiro")
    return f"satori come from {satori}, mashiro come from {mashiro}"

if __name__ == "__main__":
    app.run(host="localhost", port=8888)

  

  

13.宏的导入和注意事项

  宏也是可以导入的,在flask中,宏的导入和Python导入模块是类似的。话说为什么要有宏的导入,和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 %}
</body>
</html>

  我把之前定义的宏写在一个单独的文件里,导入通过import "宏文件的路径" as xxx, 通过xxx.宏名即可,这里必须要起名字

  或者from "宏文件的路径" import 宏名 [as xxx]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--导入的同时指定一个别名-->
    {% import "macro.html" as macro  %}
    <form action="/show" method="post">
        <!--使用的时候直接通过marco.input即可。marco相当于模块,input相当于函数或者类-->
        {{macro.input("satori","东方地灵殿")}}
        {{macro.input("mashiro","樱花庄的宠物女孩")}}
        {{macro.input("", "提交", "submit")}}
    </form>
</body>
</html>

  

14.include标签使用

include的使用非常简单,直接导入就行了,{% include "xx.html" %},相当于 ctrl+c和ctrl+v

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>但使龙城飞将在</p>
</body>
</html>

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% include "a.html" %}
    <p>不教胡马度阴山</p>
</body>
</html>

  

15.set和with语句以及模板中定义变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% set username="satori" %}
    <!--set一旦设置了,那么在全局都可以使用-->
    <h2>{{username}}</h2>

    {% with username="koishi" %}
    <h2>{{username}}</h2>
    {% endwith %}
    <!--{#with一旦设置,那么设置的值只会在with语句块内生效,所以结尾才要有endwith构成一个快
    此外with还有另一种写法,那就是
    {% with %}
    {% set username = "koishi" %}
    {% endwith %}
    这样写也是没问题的,因为set在with里面 #}-->

    <h1>{{username}}</h1>
</body>
</html>

  

16.加载静态文件

需要在项目根目录下,创建一个static文件夹,当然也可以不叫static,但是flask默认叫static。当然我们也可以在创建app的时候单独指定static_folder,类似template_folder

p{
    color: aqua;
}

  

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

  

@app.route(r"/index")
def index():
    return render_template("index.html")

  

一句话总结:无论图片啊,js啊,还是css,都使用使用{{url_for('static', filename='css|js|images/xxx.xxx')}}

17.模板继承

之前介绍了include,但是还不够灵活,因为网站一大的话,那么重合的部分就会变多,因此使用include还不是一个最好的方式。接下来介绍的模板继承非常的灵活。可以想象一下,我们博客园,四周很多内容都是不变的,如果没来一个页面都要写一遍的话,会很麻烦。因此我们可以将不变的部分先写好,在变的部分留一个坑,这就是父模板。然后字模板继承的时候,会将父模板不变的部分继承过来,然后将变得部分,也就是父模板中挖的坑填好。总结一下就是:父模板挖坑,子模板填坑。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>なんでそんなになれてんだよ</p>
    <p>雪菜と何度もキースしたんだよ</p>
    {% block 冬马小三 %}
    {% endblock %}   <!--这两行便相当于我们在父模板中挖的坑-->
    <p>どこまで私を置いてきぼりに気が済むんだよ</p>
    {% block 雪菜碧池 %}
    {% endblock %}
    <p>最初私の前から消えたのはお前だろ</p>
    {% block 打死白学家 %}
    {% endblock %}
    <p>勝手に私の手が届けないところに行ったのはお前だろう</p>

</body>
</html>

 

{% extends "base.html" %}   <!--将父模板继承过来-->

<!--接下来填好我们在父模板中挖的坑,我们挖了三个,所以这里也应该要埋三个-->
{% block 冬马小三 %}
<h2>我爱小三</h2>
{% endblock %}

{% block 雪菜碧池 %}
<h2>我爱碧池</h2>
{% endblock %}

{% block 打死白学家 %}
<h2>打死春哥,悄悄抱走冬马和雪菜</h2>
{% endblock %}

  

@app.route(r"/dsxb")
def dsxb():
    return render_template("dsxb.html")

  

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!--另外模板继承,如果父模板中挖的坑中,已经有内容了,那么子模板继承过来的时候会自动清除。-->
    <!--{#   如果想保留,需要加上{{super()}}    #}-->
    {% block 冬马小三 %}
    <p>我是父模板中的内容</p>
    {% endblock %}

    {% block 雪菜碧池 %}

    {% endblock %}

</body>
</html>

  

{% extends "base.html" %}

{% block 冬马小三 %}
{{super()}}
<h2>我是子模板中的内容</h2>
{% endblock %}

<!--{#  如果在一个块中,想使用另一个块的内容,可以通过{{self.块名()}}来实现   #}-->
{% block 雪菜碧池 %}
{{self.冬马小三()}}
{% endblock %}

  

注意:{% extend "xxx.html"  %}要放在最上面,不然容易出问题,在Django中是直接会报错的

另外,子模板中的代码一定要放在block语句块内,如果放在了外面,jinja是不会渲染的

最新文章

  1. tagfield
  2. SQL Server 2005 镜像构建手册
  3. Python3 - 时间处理与定时任务
  4. Android 设置界面的圆角选项
  5. redis 缓存技术与memcache的最大差别
  6. ExtJs目录说明
  7. Angular规范
  8. python学习之路二(字符串,字典,序列和元组)
  9. easyUI 添加排序到datagrid
  10. POJ1273(最大流)
  11. 18 Loader代码案例
  12. ASP Action函数 如何接收client传递的数据(编辑中。。。)
  13. 部署自建CA颁发证书实现https加密
  14. servlet(3)
  15. google的Python风格规范
  16. [dpdk] TSC , HPET, Timer, Event Timer,RDTSCP
  17. Python基础_私有变量访问限制
  18. Android WebView清空缓存
  19. .net如何处理高并发socket,建立高性能健壮的socket服务
  20. traceroute命令详解

热门文章

  1. Win10下Pytorch的安装和使用[斗之力三段]
  2. static 关键字解析(转)
  3. Python中enumerate函数用法详解
  4. 最短路径——Dijkstra算法以及二叉堆优化(含证明)
  5. Windows IRP
  6. Windows关机过程分析与快速关机
  7. [Leetcode] Longest consecutive sequence 最长连续序列
  8. [Leetcode] Populating next right pointer in each node ii 填充每个节点的右指针
  9. 解析Mybaits的insert方法返回数字-2147482646的原因
  10. LaTeX的图片插入及排版[转]