Bootstrap

深入剖析Jinja2语法:高效开发的关键技巧

jinja2:

模板语法:

在这里插入图片描述

from flask import Flask,render_template
app = Flask(__name__)
@app.route('/about/')
def about():
    return render_template('about.html')

当然也可以对其进行目录修改:

from flask import Flask,render_template
app = Flask(__name__,template_folder=r'temp')
@app.route('/about/')
def about():
    return render_template('about.html')

字符串:

 <h3>{{title}}</h3>

变量:

{{ foo.bar }}
{{ foo['bar'] }} # foo是一个对象 bar是一个属性

列表:

data_list是后端传给前端一种列表形式,[“aa”,“bb”,“cc”], {% for item in data_list %} 是对取出列表中每个内容,item为每个内容

        {% for item in data_list %}
            <tr>
                <th scope="row">1</th>
                <td>{{item}}</td>
                <td>Otto</td>
                <td>@mdo</td>
            </tr>
        {% endfor %}

字典:

自定义类:

class User:
    def __init__(self,username,email):
        self.username = username
        self.email = email
        
@app.route('/')
def hello_world():
    user = User(username="知了", email="[email protected]")
    person = {
        "username": "张三",
        "email": "[email protected]"
    }
    return render_template("index.html", user=user, person=person)
# user 和person 对象可以转到前端页面用于展示
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>知了传课首页</title>
</head>
<body>
<div>{{ user.username }} / {{ user.email }}</div>
<div>{{ person['username'] }} / {{ person.username }}</div>
</body>
</html>

对于键值对形式的变量,可以 对象.属性、或者对象[‘属性’] 在前端页面进行访问。

列表套字典:

 [{'id': 2, 'username': '韩超', 'password': 'qwe123', 'mobile': '1999999999'}, {'id': 4, 'username': '胡兵', 'password': 'hubing', 'mobile': '222'}]
   {% for item in data_list %}
        <tr>
            <td>{{ item.id }}</td>
            <td>{{ item.username }}</td>
            <td>{{ item.password }}</td>
            <td>{{ item["mobile"] }}</td>
        </tr>
        {% endfor %}

如果是列表套字典这种形式, {% for item in data_list %} 中的每一个item都是字典, item.属性获取对应的值。

关键字传递:

from flask import Flask,render_template
app = Flask(__name__)
@app.route('/about/')
def about():
    context={
        "hobby":"pingpang",
        "name":"hb",
        "age":20  
    }
    return render_template('about.html',**context)

流程控制:

有一个if就有一个endif,这里的语法类似javaweb中的JSTL表达式。

{% if age>18 %}
  <div>您已经满18岁,可以进入网吧!</div>
{% endif %}

@app.route("/control")
def control_statement():
    age = 18
    books = [{
        "name": "三国演义",
        "author": "罗贯中"
    },{
        "name": "水浒传",
        "author": "施耐庵"
    },]
    return render_template("control.html", age=age, books=books)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>控制语句Demo</title>
</head>
<body>
{% if age>18 %}
  <div>您已经满18岁,可以进入网吧!</div>
{% elif age==18 %}
  <div>您刚满18岁,需要父母陪同才能进入!</div>
{% else %}
  <div>您未满18岁,不能进入网吧!</div>
{% endif %}

{% for book in books %}
  <div>图书名称:{{ book.name }},图书作者:{{ book.author }}</div>
{% endfor %}
</body>
</html>

过滤器:

​ 变量可以通过 过滤器 修改, {value|过滤器},可以使用jinja2中自带的过滤器,也可以自己定义过滤器,过滤器相当于Linux下的管道符。

内置过滤器:
{{ name|striptags|title }} # 会移除 name 中的所有 HTML 标签并且改写 为标题样式的大小写格

数量:

{{ post.comments.all()|length }}
{{ question.answers|length }}
{{ post.comments.count() }}

在html里面也可以做过滤查询:

          {% for comment in post.comments.filter_by(is_active=True).all() %}
 <div class="comment-group">
      <h3>评论列表</h3>
      <ul class="comment-list-group">
        {% for comment in post.comments.filter_by(is_active=True) %}
    
          <li>
            <div class="comment-content">
              <p class="author-info">
                <span>{{ comment.author.username }}</span>
                <span>{{ comment.create_time }}</span>
              </p>
              <p class="comment-txt">
                {{ comment.content }}
              </p>
            </div>
          </li>
        {% endfor %}
      </ul>
    </div>

默认值:

{{ user.signature or '' }} 这段代码使用了 or 运算符来提供一个默认值。如果 user.signature 不存在或为空,那么 user.signature or '' 的结果就是空字符串 ''

自定义过滤器:

如果我们不想对数据进行直接渲染,进行一些操作在进行展示,我们可以自己定义一个函数,然后再前端调用.

# 自定义函数 value就是我们进行操作的值
def datetime_format(value, format="%Y年%m月%d日 %H:%M"):
    return value.strftime(format)
# 将datetime_format 命名为dformat 可以直接在前端调用
app.add_template_filter(datetime_format,"dformat")

@app.route("/filter")
def filter_demo():
    user = User(username="知了xxxx", email="[email protected]")
    mytime = datetime.now()
    return render_template("filter.html", user=user, mytime=mytime)

对象| 方法

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>过滤器使用demo</title>
</head>
<body>
<div>{{ user.username }}-{{ user.username|length }}</div>  
<div>{{ mytime|dformat }}</div>
</body>
</html>

{{ user.username|length }} 可以理解为内置属性,{{ mytime|dformat }} 可以理解为对mytime执行dformat(自定义函数)。

测试器:

转义:

少量转义:

{{ '{{' }}

大量转义:

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

放在一个 {% raw %}{% endraw %} 块内部,可以不进行填充。

使用safe对其表示不要转义:

{{ post.content|safe }}

相关查询:

    post = db.relationship("PostModel", backref=db.backref('comments', order_by=create_time.desc(), lazy="dynamic"))

相关全局对象:

      # 对当前用户的信息进行修改 
        g.user.username = username
        g.user.signature = signature
        db.session.commit()

网页继承:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        {% endblock %}
    </div>
</body>

​ 在上面的父模板,我们使用了 {% block head %} 、{% block title %} 、 {% block content %}、{% block footer %} ,我们的子模板只需要重写一下这几个块即可.

{% extends "base.html" %} //继承 
{% block title %}Index{% endblock %} //重写title块
{% block head %}
    {{ super() }} //用于调用基础模板中同名块的内容
    <style type="text/css">  // 这是新添加的内容 
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %} //重写 content 块
    <h1>Index</h1>
    <p class="important">
      Welcome on my awesome homepage.
    </p>
{% endblock %}
//还有注意的一点是  {% block footer %} 即继承下来 因为没有重写

{% extends "base.html" %} 表示该网页继承base.html
{% block body %}
我是子模板的body
{% endblock %}  #表示将内部内容填充到 父亲的{% block body %} {% endblock %} 中
@app.route("/child1")
def child1():
    return render_template("child1.html")


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

这是base.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}{% endblock %}</title>
</head>
<body>
<ul>
  <li><a href="#">首页</a></li>
  <li><a href="#">新闻</a></li>
</ul>
{% block body %}
{% endblock %}
<footer>这是底部的标签</footer>
</body>
</html>

child1.html

{% extends "base.html" %}
{% block title %}
我是子模板的标题
{% endblock %}
{% block body %}
我是子模板的body
{% endblock %}

child2.html

{% extends "base.html" %}

{% block title %}
我是child2
{% endblock %}

{% block body %}
我是child2
{% endblock %}

Ajax:

与ajax的结合,Ajax只是起到了一个发送请求返回数据的作用。

在这里插入图片描述

function refreshTitle() {
	$.ajax({
        type:'GET'
        url: "http://127.0.0.1:5000/Title" + "?n="+ Math.random()
        dataType:'json',
        success: function (data) {
                console.log(data);
                $('#echart1_title').text(data['title'][o])
                $('#echart2_title').text(data['title'][1])
                $('#echart4_title').text(data['title'][2])
                $('#echart5_title').text(data['title'][3])
                $('#echart6_title').text(data['title'][4])
    }
})
}    
        
    refreshTitle()
    var processCounter =window.setInterval('refreshTitle()',360000) //当时
  • dataType是要求为String类型的参数,预期服务器返回的数据类型,如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递。

    • xml:返回XML文档 ,目前基本不用了
    • HTML:返回纯文本HTML信息;包含的script标签会在插入DOM时执行,有些写网站还在有,比如豆瓣,他的ajax返回来的就是HTML的标签内容,就是核心的html标签,这些标签会自动插入到合适的位置。
    • script:返回纯文本JavaScript代码。不会自动缓存结果。除非设置了cache参数。注意在远程请求时(不在同一个域下),所有post请求都将转为get请求。
    • json:返回JSON数据。
    • jsonp:JSONP格式。使用JSONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
    • text:返回纯文本字符串

    success:

    • Function类型的参数,请求成功后调用的回调函数,有两个参数

    • 由服务器返回,并根据dataType参数进行处理后的数据。

    function(data, textStatus){
    //data可能是xmlDoc、jsonObj、html、text等等 this;  
    //调用本次ajax请求时传递的options参数     
    }
    

    同步提交:当用户发送请求时,当前页面不可以使用,服务器响应页面到客户端,响应完成,用户才可以使用页面。

    异步提交:当用户发送请求时,当前页面还可以继续使用,当异步请求的数据响应给页面,页面把数据显示出来 。

console.log(xhr.status);//状态码
 console.log(xhr.statusText);//状态字符串
console.log(xhr.getAllResponseHeaders());//所有响应头
console.log(xhr.response);//响应体
xhr.response: 返回响应的主体数据。根据设置的responseType属性,可以是字符串、JavaScript对象、XML文档、Blob对象等。
xhr.responseText: 返回响应的主体数据作为字符串。如果设置了responseType为其他类型,则该属性为空字符串。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jQuery 发送 AJAX 请求</title>
    <link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
    <div class="container">
        <h2 class="page-header">jQuery发送AJAX请求 </h2>
        <button class="btn btn-primary">GET</button>
        <button class="btn btn-danger">POST</button>
        <button class="btn btn-info">通用型方法ajax</button>
    </div>
    <script>
        $('button').eq(0).click(function(){
            $.get('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
                console.log(data);
            },'json');
        });

        $('button').eq(1).click(function(){
            $.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
                console.log(data);
            });
        });

        $('button').eq(2).click(function(){
            $.ajax({
                //url
                url: 'http://127.0.0.1:8000/jquery-server',
                //参数
                data: {a:100, b:200},
                //请求类型
                type: 'GET',
                //响应体结果
                dataType: 'json',
                //成功的回调
                success: function(data){
                    console.log(data);
                },
                //超时时间
                timeout: 2000,
                //失败的回调
                error: function(){
                    console.log('出错啦!!');
                },
                //头信息
                headers: {
                    c:300,
                    d:400
                }
            });
        });

    </script>
</body>
</html>

路由反转:

Jinja2语法中,为了减少对url的使用,选择使用url_for()函数来进行反转得到路由函数。

CSSjs继承:

@app.route('/static')
def static_demo():
    return render_template("static.html")
静态文件:

static.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
    <-- 下面就是会用url_for() 函数导入相应的静态文件,比如css,js,html->
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> 
  <script src="{{ url_for('static', filename='js/my.js') }}"></script>
</head>
<body>
<img src="{{ url_for('static', filename='images/ironman.jpg') }}" alt="">
</body>
</html>

在这里插入图片描述

url_for('static', filename='js/my.js')  # 相当于在static下的js/my.js 相当于路径的拼接
{% block head %}
  <link rel="stylesheet" href="{{ url_for('static',filename='front/css/sign.css') }}">
{% endblock %}
内部反转:
from flask import Flask,url_for
app = Flask(__name__)
@app.route('/article/<id>/')
def article(id):
    return '%s article detail' % id

@app.route('/')
def index(request):
    print(url_for("article",id=1)) # article 为路由函数 id=1 路由函数中的参数,如果还有多的参数,会当作查询字符串拼接
    return "首页"
蓝图反转:

当存在蓝图的时候,我们应该这样写:

​ 用url_for生成蓝图的url,使用的格式是:蓝图名称+.+视图函数名称。比如要获取admin这个蓝图下的index视图函数的url,应该采用以下方式:

url_for('admin.index')

总结:

​ 通过本文的介绍,我们深入了解了Jinja2模板引擎的核心语法和功能。从前后端参数传递到字典和数组的操作,再到流程控制过滤器、测试器和路由反转的应用,我们掌握了在开发中常用的关键技巧。同时,我们还学习了如何利用模板继承来提高代码的可维护性和可扩展性。

​ Jinja2语法的灵活性和强大功能为开发者提供了广阔的可能性,无论是构建简单的网页还是复杂的应用程序,都能从中受益匪浅。希望本文对您在使用Jinja2时有所启发,并在您的开发工作中发挥积极的作用。

​ 继续探索和实践Jinja2语法,您将不断发现它的魅力和实用性。祝愿您在使用Jinja2构建出令人惊艳的Web应用程序!

;