flask之二 模板相關

flask之二

預熱

  • 在渲染模板的時候,默認會從項目根路徑下的templates目錄下查找模板
  • 如果想要指定模板路徑的時候,就在初始化APP的時候,這樣操作即可:
    app = Flask(__name__,template_folder='C:/templates') #template_folder可以指定模板位置

    模板傳參

  • 在使用render_template渲染模板的時候,可以傳遞關鍵字參數,以後直接在模板中使用就可以了
  • 如果參數過多的話,那麼就可以將所有的參數放到一個字典中,然後再傳這個參數的時候使用**將字典打散成關鍵字參數。

    小例子:

  • my_template.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.debug = True
    @app.route('/')
    def hello_world():
    context = {
        'username': 'wanghui',
        'age':19,
        'children':{
            'user':'ccc',
            'type':'stu',
        }
    }
    return render_template('index.html', **context)
    # return render_template('index.html',context=context)
    # return render_template('index.html',username='wanghui',age=19)
    if __name__ == '__main__':
    app.run()
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>my blog</title>
    </head>
    <body>
    <h1>這是模板渲染的數據</h1>
    {#<p>{{ username }}</p>#}
    {#<p>{{ age }}</p>#}
    {{ context.username }}
    {{ context.age }}
    <p>{{ username }}</p>
    <p>{{ children.user }}</p>
    </body>
    </html>

    模板中的url_for

    模板中的url_for和視圖函數中的url_for是類似的,也是傳遞視圖函數的名字,也可以傳遞參數。使用的時候,需要在url_for兩邊加上一個{{ url_for('func_name'),ref='/',id='1'}}

  • templates.py
    from flask import Flask,render_template,url_for
    app = Flask(__name__)
    app.debug = True
    @app.route('/')
    def hello_world():
    return render_template('index.html')
    @app.route('/accounts/login/<id>/')
    def login(id):
    return render_template('login.html')
    if __name__ == '__main__':
    app.run(port=8888)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>my blog</title>
    </head>
    <body>
    <h1>這是從模板中渲染的</h1>
    <p><a href="{{ url_for('login',ref='/',id='1') }}">登陸</a></p>
    </body>
    </html>
  • templates/login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Login page</title>
    </head>
    <body>
    <h1>這是登錄頁面</h1>
    {#{{ 用來存放變量 }}#}
    {#{% 用來執行函數或者邏輯代碼 %}#}
    </body>
    </html>

    過濾器

    有時候我們需要在模板中對一些變量進行處理,那麼就必須要類似於python中的函數一樣,可以將這個值傳到函數中,然後做一些操作。在模板中過濾器相當於是一個函數,把當前的變量傳入到過濾器中,然後過濾器會根據自己的功能,再返回相應的值,之後再將結果渲染到頁面上。

  • 基本語法:{{ variable |過濾器的名字 }}
    guo
  • abs(value):返回一個數值的絕對值。 例如:-1|abs。
  • default(value,default_value,boolean=false):如果當前變量沒有值,則會使用參數中的值來代替。name|default('xiaotuo')——如果name不存在,則會使用xiaotuo來替代。boolean=False默認是在只有這個變量爲undefined的時候纔會使用default中的值,如果想使用python的形式判斷是否爲false,則可以傳遞boolean=true。也可以使用or來替換。
  • escape(value)或e:轉義字符,會將<、>等符號轉義成HTML中的符號。例如:content|escape或content|e。
  • first(value):返回一個序列的第一個元素。names|first。
  • format(value,*arags,**kwargs):格式化字符串。例如以下代碼:
    {{ "%s" - "%s"|format('Hello?',"Foo!") }}\
    將輸出:Helloo? - Foo!
  • last(value):返回一個序列的最後一個元素。示例:names|last。
  • length(value):返回一個序列或者字典的長度。示例:names|length。
  • join(value,d=u''):將一個序列用d這個參數的值拼接成字符串。
  • safe(value):如果開啓了全局轉義,那麼safe過濾器會將變量關掉轉義。示例:
    content_html|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:截取字符串前面和後面的空白字符。
    string(value):將變量轉換成字符串。
    wordcount(s):計算一個長字符串中單詞的個數。
  • default過濾器詳解:
    如果某個變量使用方式是{{ value|default('默認值')}},如果value這個key不存在的話就使用過濾器提供的默認值;如果類似於python中判斷一個值是否爲False(例如:空字典,空字符串,空列表的話)那麼久必須要傳遞另外一個參數{{ value | default('默認值',boolean=True)}};
    可以使用or來替換default('默認值',boolean=True)(例如{{ siginature or '此人很懶沒有留下任何說明'}})
    例子:
  • defaulte_falter.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def index():
    context = {
        'position':-9,
        'signature':'',
        #'signature':'this ismy blog'
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>MyBlog</title>
    </head>
    <body>
    {#<p>個性簽名:{{ signature|default('此人很懶沒有留下任何說明!',boolean=True) }}</p>#}
    <p>個性簽名:{{ signature or '此人很懶沒有留下任何說明!'}}</p>
    </body>
    </html>
  • esacape:轉義過濾器
    • safe過濾器:可以關閉一公分字符串的自動轉義
    • escape過濾器:對某個字符串進行轉義
    • autoescape過濾器:可以對其代碼框內的代碼塊關閉自動轉義
    • first:返回序列中的第一個元素
  • last:返回序列中的最後一個元素
  • format:格式化輸出
  • length:長度計算
  • int:轉換成整數
  • replase:舊字符串換成新的
  • truncate:指定長度截取(結合striptags去除掉html字段之後截取純淨字符串然後按字數去做預覽頁填充)
  • striptags:去除標籤中的html字段
  • worldcount(s):統計一個長字符串中的單詞數
    小例子:
  • escape.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def hello_world():
    context = {
        'position':-9,
        'signature':'<script>alert("Hello world!")</script>',
        'persons':['abc','def'],
        'age':"18",
        'article':'hello hello xxooo xxooo!!'
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True,port=8080)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>MyBlog</title>
    </head>
    <body>
    {#{% autoescape off %}#}
    {#<p>個性簽名:{{ signature }}</p>#}
    {#{% endautoescape %}#}
    <p>{{ signature|safe }}</p>
    <p>{{ persons|first }}</p>
    <p>{{ persons[0] }}</p>
    <p>{{ persons|last }}</p>
    <p>{{ persons[-1] }}</p>
    <p>{{ "我的名字是%s"|format("hello word!") }}</p>
    <p>{{ "人數是 %d"|format(persons|length) }}</p>
    {% if age|int == 18 %}
    <p>年齡是18歲</p>
    {% else %}
    <p>年齡不是18歲</p>
    {% endif %}
    <p>{{ article|replace('hello','sssssz') }}</p>
    <p>{{ article|truncate(length=5) }}</p>
    <p>{{ signature|striptags }}</p>
    </body>
    </html>

    自定義模板過濾器

    1. 在python文件中寫好自己的過濾器(本質上就是一個函數)
    2. 如果要在模板中調用這個過濾器,那就需要在這個函數上加一個裝飾器@app.template_filter('過濾器名稱')
    3. 自動加載的話就在app下添加
      app.config['TEMPLATES_AUTO_RELOAD'] = True
  • 小例子:
  • define_filter.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    @app.route('/')
    def hello_world():
    context={
        'article':'anyway hello anyway hello abccc'
    }
    return render_template('index.html',**context)
    @app.template_filter('cut')
    def cut(value):
    vaule = value.replace("hello","sbsb")
    return value
    if __name__ == '__main__':
    app.run(debug=True,port=9090)**
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>myblog</title>
    </head>
    <body>
    <p>{{ article|cut }}</p>
    </body>
    </html>

    實戰自定義過濾器

  • 時間處理(從現在到發帖的時間差)
  • shizhan.py
    from flask import Flask,render_template
    from datetime import datetime
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    @app.route('/')
    def index():
    context={
        'article':'aaa bbb ccc',
        'create_time':datetime(2018,02,23,10,12,11)
    }
    return render_template('index.html',**context)
    @app.template_filter('handle_time')
    def handle_time(time):
    '''
    1.距離現在的時間多久,如果間隔在一分鐘以內就表示剛剛
    2.在一小時以內就顯示xx分鐘前
    3.在24小時以內就顯示xx小時前
    4. 在一個月之內就顯示多少天之前
    5. 否則就顯示具體的時間
    :param time:
    :return:
    '''
    if isinstance(time,datetime):
        now = datetime.now()
        timestamp = (now - time).total_seconds() #獲取間隔秒數
        if timestamp < 60:
            return "剛剛"
        elif timestamp >=60 and timestamp<= 60*60:
            minutes = timestamp/60
            return "%s分鐘前",int(minutes)
        elif timestamp >= 60*60 and timestamp <= 60*60*24:
            hours = timestamp/(60*60)
            return "%s小時前",int(hours)
        elif timestamp >= 60*60*24 and timestamp<= 60*60*24*30:
            days = timestamp/(60*60*24)
            return "%s天前",int(days)
    else:
        return time.strftime('%Y-%m-%d %H:%M')
    if __name__ == '__main__':
    app.run(port=9092,debug=True)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>MyBlog</title>
    </head>
    <body>
    <p>發表時間:{{ create_time|handle_time }}</p>
    </body>
    </html>

    條件判斷

    For循環

    jinjia2中的for循環,跟python中的for循環基本是一致的,也是用for in形式;
    而且可以便利所有的序列以及迭代器,但是唯一不同的是jinjia2中的for循環沒有breakcontinue

  • 小例子:
  • for_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def hello_world():
    context = {
        'users':['user01','user02','user03'],
        'person':{
            'username':'wanghui',
            'age':21,
            'country':'china',
        },
        'books':[
            {
                'name':'sk1',
                'author':'saa',
                'price':100,
            },
            {
                'name': 'aaaeede1',
                'author': 'se232aa',
                'price': 103,
            },
            {
                'name': 'AAAew',
                'author': 'VVVeqwea',
                'price': 190,
            },
            {
                'name': 'skfdfds1',
                'author': 'sdfsfsdfdaa',
                'price': 30,
            }
        ]
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>MyBlog</title>
    </head>
    <body>
    <ul>
    {% for user in users %}
        <p>{{ user }}</p>
    {% endfor %}
    </ul>
    <table>
    <thead>
        <tr>
            <th>用戶名</th>
            <th>年齡</th>
            <th>國家</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            {% for key,value in person.items() %}
                 <td>{{ value }}</td>
            {% endfor %}
        </tr>
    </tbody>
    <table>
    <thead>
    <tr>
        <th>ID</th>
        <th>書名</th>
        <th>作者</th>
        <th>價格</th>
        <th>總數</th>
    </tr>
    </thead>
    <tbody>
        {% for book in books %}
            {% if loop.first %}
                <tr style="background: red">
                {% elif loop.last %}
                <tr style="background: blue">
                {% else %}
                <tr>
            {% endif %}
            <td>{{ loop.index }}</td>
            <td>{{ book.name }}</td>
            <td>{{ book.author }}</td>
            <td>{{ book.price }}</td>
            <td>{{ loop.length }}</td>
        </tr>
        {% endfor %}
    </tbody>
    </table>
    </table>
    <table border="1px">
    <tbody>
    {% for x in range(1,10) %}
        <tr>
        {% for y in range(1,x+1) if y <= x %}
            <td>{{ y }}*{{ x }}={{ x*y }}</td>
        {% endfor %}
        </tr>
    {% endfor %}
    </tbody>
    </table>
    </body>
    </html>

    模板中的宏跟python中的函數類似,可以傳遞參數,但是不能有返回值
    使用宏的時候,參數可以是默認值

  • 小例子:
  • macro.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.config['DEBUG'] = True
    @app.route('/')
    def hello_world():
    return render_template('index.html')
    if __name__ == '__main__':
    app.run(port=9999)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Macro</title>
    </head>
    <body>
    {% macro input(name="",value="",type="text") %}
        <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
    <h1>登陸頁面</h1>
    <table>
    <tbody>
    <tr>
        <td>用戶名:</td>
        <td>{{ input('username') }}</td>
    </tr>
    <tr>
        <td>密碼:</td>
        <td>{{ input('password',type='password') }}</td>
    </tr>
    <tr>
        <td></td>
        <td>{{ input(value='提交',type='submit') }}</td>
    </tr>
    </tbody>
    </table>
    </body>
    </html>

    宏的導入

    在真實的開發中,會將一些常用的宏單獨放在一個文件中,在需要使用的時候,再從這個文件中進行導入。
    import語句的用法跟python中的import類似,可以直接import...as...,也可以from...import...或者from...import...as...,假設現在有一個文件,叫做forms.html,裏面有兩個宏分別爲input和textarea,如下:

注意事項:
a. inport宏文件 as xxx
b. from 宏文件路徑 import 宏的名字 [as xxx]
c. 宏文件的路徑,不要以相對路徑去找,都要以templates作爲絕對路徑去找
d. 如果想要在導入宏的時候,就把當前末班的一些參數傳遞給宏所在的模板,那麼就應該在導入的時候使用
with context

  • 小例子:
  • macros.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.config['DEBUG'] = True
    @app.route('/')
    def hello_world():
    return render_template('index/index.html')
    if __name__ == '__main__':
    app.run(port=9999)
  • templates/macros/macros.html
    {% macro input(name="",value="",type="text") %}
    <input type="{{ type }}" name="{{ name }}" value="{{ username }}">
    {% endmacro %}
  • templates/index/index.html
    {#{% from "macros.html" import input as inp %}#}
    {% import "macros/macros.html" as macros with context %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Macro</title>
    </head>
    <body>
    <h1>登陸頁面</h1>
    <table>
    <tbody>
    <tr>
        <td>用戶名:</td>
        <td>{{ macros.input('username') }}</td>
    </tr>
    <tr>
        <td>密碼:</td>
        <td>{{ macros.input('password',type='password') }}</td>
    </tr>
    <tr>
        <td></td>
        <td>{{ macros.input(value='提交',type='submit') }}</td>
    </tr>
    </tbody>
    </table>
    </body>
    </html>

    include標籤

    1. 這個標籤相當於是將指定模板中的代碼複製粘貼到當前的位置
    2. include標籤,如果要繼續使用父模板中的變量,直接用就可以了
    3. include的路徑也和import一樣,需要從templates爲根,不要以相對路徑去找。
  • 小例子:
  • include_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD']
    @app.route('/')
    def hello_world():
    return render_template('index.html',username='wanghui')
    @app.route('/detail/')
    def detail():
    return render_template('course_detail.html')
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>MyBlog</title>
    </head>
    <body>
    {% include "common/header.html" %}
    <div class="content">中間的</div>
    {% include "common/footer.html" %}
    <ul>{{ username }}</ul>
    </body>
    </html>
  • templates/course_detail.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    {% include "common/header.html" %}
    <div class="content">文章詳情!</div>
    {% include "common/footer.html" %}
    </body>
    </html>
  • templates/common/header.html
    <style>
        .nav  ul{
            overflow: hidden;
        }
        .nav ul li{
            float: left;
            margin: 0 20px;
        }
    </style>
    <nav class="nav">
    <ul>
        <li>首頁</li>
        <li>博客詳情</li>
        <li>教程中心</li>
        <li>關於我</li>
    </ul>
    </nav>
  • templates/common/footer.html
    <footer>這是底部</footer>

set with語句

  • 在模板中,可以使用set來定義變量;一旦定義了這個變量。那麼在後面的代碼中,都可以使用這個變量。
  • with語句定義的變量,只能在with的代碼塊中使用。超出with代碼塊,則不能使用
  • with不一定要跟一個變量,也可以是一個空的with語句,以後要用的話,就在with中使用set定義的變量來使用。
<body>
{% set username='wanghui' %}
<p>用戶名:{{ username }}</p>
{% with %}
    {% set  cla***oom='2018' %}
    <p>班級:{{ cla***oom }}</p>
{% endwith %}
<p>別的班級{{ cla***oom }}</p>
</body>

加載靜態文件

  • 加載靜態文件使用的是url_for函數,第一個參數爲static,第二個參數是filename='path'
  • 路徑查找要以static目錄作爲根目錄
  • 小例子:
    • static_ex.py
      from flask import Flask,render_template
      app = Flask(__name__)
      app.config.update({
      'DEBUG':True,
      'TEMPLATES_AUTO_RELOAD':True,
      })
      @app.route('/')
      def hello_world():
      return render_template('index.html')
      if __name__ == '__main__':
      app.run()
  • static/css/index.css
    body{
    background: pink;
    }
  • static/js/index.js
    alert('hello user!')
  • static/imgs/sas.jpg
    圖片
  • templates/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('static',filename="css/index.css") }}">
    <script src="{{ url_for('static',filename="js/index.js") }}"></script>
    </head>
    <body>
    <img src="{{ url_for('static',filename='imgs/asa.jpg') }}" alt="">
    </body>
    </html>

    模板繼承

    爲什麼需要模板繼承?

  • 可以將一些公用的代碼單獨抽取出來放到一個父模板中,以後子模板直接繼承就給可以使用了。
  • 這樣可以減少重複性的代碼,並且以後代碼修改起來也很方便

    模板繼承的語法

  • 使用extends語句來指明繼承的父模板。父模板的路徑也就是相對於templates文件夾下的絕對路徑。例子如下{% extends 'base.html' %}

block語法

一般在父模板中只能定義一些共性公用的代碼,子模板可能要根據不同的需求實現不同的代碼。這時候父模板就應該提供一個接口,讓子模板來實現。從而實現業務的具體功能。

  • 在父模板中
    {% block body_block %}
    <p>我是base下的</p>
    {% endblock %}
  • 在子模板中
    {% block body_block %}
    <p>我是index的內容</p>
    {% endblock %}

    調用父模板代碼block中的代碼

    默認情況下,字幕版實現了父模板定義的block,那麼子模板中block的代碼就會覆蓋掉父模板中的代碼,要想保留父模板中的block的話就是用{{ super() }}來實現

  • 父模板的內容:
    {% block body_block %}
    <p style="background: red">base.html</p>
    {% endblock %}
  • 子模板中的內容:
    {% extends 'base.html' %}
    {% block body_block %}
    {{ super() }}
    <p style="background: green">我是index的內容</p>
    {% endblock %}

    調用另外一個block中的代碼

    在另外一個模板中使用其他模板中的代碼,可以使用{{ self.blockname() }}即可

  • 父模板
    <title>{% block title %}
    {% endblock %}</title>
    <body>
    {% block body_block %}
    <p style="background: red">base.html</p>
    {% endblock %}
    </body>
  • 子模板:
    {% extends 'base.html' %}
    {% block title %}
    MyIndex
    {% endblock %}
    {% block body_block %}
    {{ super() }}
    {{ self.title() }}
    <p style="background: green">我是index的內容</p>
    {% endblock %}

    其他注意事項

  • 繼承的代碼必須放在子模板中的第一行{% extends 'base.html' %}
  • 子模板中要實現自己的代碼,要放到block中,不然不生效

    繼承的例子:

  • inherit_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config.update({
    'DEBUG':True,
    'TEMPLATES_AUTO_RELOAD':True
    })
    @app.route('/')
    def index():
    return render_template('index.html')
    @app.route('/detail/')
    def detail():
    return render_template('course_detail.html')
    if __name__ == '__main__':
    app.run()
  • templates/base.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>{% block title %}
    {% endblock %}</title>
    <style>
        .nav  ul{
            overflow: hidden;
        }
        .nav ul li{
            float: left;
            margin: 0 20px;
        }
    </style>
    </head>
    <body>
    <nav class="nav">
    <ul>
        <li>首頁</li>
        <li>博客詳情</li>
        <li>教程中心</li>
        <li>關於我</li>
    </ul>
    </nav>
    {% block body_block %}
    <p style="background: red">base.html</p>
    {% endblock %}
    <footer>這是底部</footer>
    </body>
    </html>
  • templates/index.html
    {% extends 'base.html' %}
    {% block title %}
    MyIndex
    {% endblock %}
    {% block body_block %}
    {{ super() }}
    {{ self.title() }}
    <p style="background: green">我是index的內容</p>
    {% endblock %}
  • templates/course_detail.html
    {% extends 'base.html' %}
    {% block body_block %}
    <p>this is course </p>
    {% endblock %}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章