flask框架 模板相关

模板

什么是模板引擎?

实现视图的业务逻辑和返回给前端的页面逻辑分离的工具,我们称之为模板引擎。

为什么要有模板引擎?

如果没有模板引擎,直接把模板的html代码写在视图函数里面,会给程序员的日常开发带来多大的困扰,模板引擎帮我们分开了业务逻辑和页面逻辑,并且我们每一次修改一个大字符串会非常不方便,模板引擎还可以读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,然后返回给浏览器,这个过程我们称之为渲染。

Flask中如何使用模板引擎?

flask使用jinjia2作为框架的默认模板引擎,jinjia2是基于Python的模板引擎,功能比较类似以phpsmartyJ2eeFreemarkervelocityjinjia2除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板的输出。并且jinja2不限制模板的格式为html,可以是任何格式的文本文件。

模板引擎传参

传参的时候要应用render_template(),利用render_template的第二个参数进行传参,该函数在定义的时候,第二个参数是可变长形参,所以在传值的时候我们可以传入多个关键字实参。

我们定义的视图函数内部调用渲染模板:

render_template('list.html',info=info,html="<h1>jsaon-gdx</h1>",html1=func1)

源码接收关键字实参:

def render_template(template_name_or_list, **context):

注意:

​ render_template传参的时候以关键字实参进行传参。可以传多个,可以使用**将字典打散成关键字实参。

def demo2():
    context_dict = {"name": "mark",
               "age": "mark",
               "sex": "girl",
                "other_info":{"tel":1365,
                               "qq":565656}}

    return render_template('index.html',**context_dict)
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板传参</title>
</head>
<body>
    {{name}}
    {{age}}
    {{sex}}
    {{other_info.tel}}
    {{other_info["qq"]}}
</body>
</html>

模板加载静态文件

在模板中加载静态文件的时候也要使用到url_for()函数,去寻找具体的静态文件资源。第一个参数是定位到static文件夹,filename参数定位到static文件夹内的具体资源。

{{ url_for('static',filename='相对于static文件夹的路径') }}

实例:

项目目录:

│  app.py
│
├─static  # 文件夹
│  ├─css  # 文件夹
│  │      demo.css
│  │
│  ├─images  # 文件夹
│  │      1.png
│  │
│  └─js  # 文件夹
│          demo.js
│
├─templates  # 文件夹
     index.html

app.py

...

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

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>静态文件加载</title>
    
    <link rel="stylesheet" href="{{ url_for('static',filename='css/demo.css') }}">
    <script src="{{ url_for('static',filename='js/demo.js') }}"></script>
    
</head>
<body>
    <img src="{{ url_for('static',filename='images/1.png') }}">
</body>
</html>

demo.css

body{
    background: red;
}

demo.js

alert('hello world')

模板的继承

jinja2的模板的继承可以把一些公共的代码定义到一个基模板中,以后所有的子模板直接继承基模板,在子模板被渲染是会自动包含继承基模板的内容,通过模板的继承可以避免在多个模板中编写重复代码。

具体实现:

在基模板中定义一些公共的代码,子模板会继承这些公共的代码,但是子模板需要根据自己的需求去实现不同的代码,这个时候就需要在基模板中提供一些接口,以便子模板实现自己的业务需求。

1.基本写法

在基/父模板中定义接口(block)

{% block main %} {# main是自定义的变量名 #}

{% endblock %}

在子模板中继承父模板,并且重写接口(block)

{% extends 'base.html' %} {# extends 后面跟的参数是导入的基模板相对于templates的路径 #}
{% block main %}
    
{% endblock %}

2.子模板中调用父模板代码block中的代码

基模板中

{% block main %}
<p>父模板中main中原有的内容</p>

{% endblock %}

子模板中:

{% block main %}
    {{ super() }}   {# 保留基模板中本块的代码 #}
    <p>子模板中重写main的内容 </p>
{% endblock %}

3.在子模板中调用其他block中的代码:

子模板中:

{% block main %}
    {{ self.demo() }} {# self.其他block名字 #}
    <p>子模板中重写main的内容 </p>
{% endblock %}

4.子模板中的想定义自己的代码只能放到block中,否则无效

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父模板</title>
    <link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}">
</head>
<body>
    <form class="navbar-form navbar-left" role="search">
      <div class="form-group">
        <input type="text" class="form-control" placeholder="Search">
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
    <div style=" visibility:hidden;display:block;font-size:0;clear:both;
            height:50px"></div>


    {% block main %}
        <p>父模板中main中原有的内容</p>

    {% endblock %}
   <br>
   <br>
   <br>
    {% block demo %}
        <p>demo中原有的内容</p>
    {% endblock %}


<div style=" visibility:hidden;display:block;font-size:0;clear:both;
            height:0"></div>
<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</a></li>
    <li><a href="#">4</a></li>
    <li><a href="#">5</a></li>
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>

</body>
</html>

detail.html

{% extends 'base.html' %}
{% block demo %}
    <p>子模板中重写demo的内容</p>
{% endblock %}
{% block main %}
    {{ super() }}   {# 保留基模板中本block的代码 #}
    {{ self.demo() }} {# 调用demo block的代码 #}
    <p>子模板中重写main的内容 </p>
{% endblock %}

app.py 注意:app.config.update(TEMPLATE_AUTO_RELOAD=True)语句用于每次都重新加载模板文件

from flask import Flask, render_template

app = Flask(__name__)
app.config.update(TEMPLATES_AUTO_RELOAD=True)

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

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


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

子模板运行效果

模板小案例

flask框架前端的反向解析用的也是后端的url_for("函数名"),<a href="{{url_for('sb',nid=k)}}">查看详细</a>可以解析出路由和浏览器传来的动态路由(nid=k),点击a标签跳转路由。

 Markup:flask中后端过滤器,表明后端Markup传来的html是安全的,可以渲染。
 
{{html|safe}} :后端没有使用Markup过滤器表明html是安全的,前端可以使用模板过滤器,渲染html,类似Django的过滤器。

后端传的变量是一个函数名(html1=func1)给前端,前端拿到函数名加括号使用模板语法就可以调用后端写的函数,还可以在模板语法中给该函数传参,例:{{html1("-DSB","-SB")}}。Django中的前端使用函数或类进行渲染是不需要加括号的,内部会自动加括号调用函数或实例化一个对象。


render_template('box/login.html')的路径是template文件夹的相对路径

from flask import Flask,render_template,request,redirect,session,url_for,Markup
app = Flask(__name__)
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'

USERS = {
    1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
    2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
    3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}
def func1(st,st1):
    return Markup(f"<h1>jsaon-gdx{st}{st1}</h1>") # flask中后端过滤器,表明后端Markup传来的html是安全的,可以渲染。

@app.route('/list',methods=['GET'])
def list():
    info=USERS

    return render_template('list.html',info=info,html="<h1>jsaon-gdx</h1>",html1=func1)
@app.route('/detail/<int:nid>',methods=['GET'],endpoint="sb")
def detail(nid):

    return "ok"

if __name__ == '__main__':
    app.run()
<!--list.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
{% for k,v in info.items() %}
        <tr>
            <td>{{k}}</td>
            <td>{{v.name}}</td>
            <td>{{v['name']}}</td>
            <td>{{v.get('name')}}</td>
            <td><a href="{{url_for('sb',nid=k)}}">查看详细</a></td>
        </tr>
{% endfor %}
{{html|safe}} 
{{html1("-DSB","-SB")}}

</body>
</html>
<!--index.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
{{sb(1,2)}}
{{1|db(2,3)}}
</body>
</html>
原文地址:https://www.cnblogs.com/zhangchaocoming/p/12348601.html