flask04-模板

04-01 模板

1 重定向

1.1 什麼是重定向?

重定向,顧名思義,就是從新定向到一個新的位置,好比咱們在瀏覽器的頁面自動跳轉到了另外一個頁面,又好比訪問了一個頁面,而後觀察網址以後並非咱們輸入的網址,這個過程就是重定向完成的。javascript

1.2 爲何要有重定向?

  http狀態碼 應用場景 優點
暫時性重定向 302 訪問一些須要權限的頁面,會自動重定向到權限認證的頁面 重定向在設計上會提高用戶體驗
永久性重定向 301 廢棄原有的網址被訪問,會自動重定向到新的網址確保用戶訪問成功 重定向在設計上會提高用戶體驗,有利於搜索引擎優化

例1:訪問淘寶的時候,你選擇了已經購買的商品,可是你並無登陸過淘寶,那麼這個時候若是隻是提示 「請登陸再訪問!」,那麼相信這種設計是留不住用戶的,不如直接爲用戶重定向到登陸頁面。css

例2:好比想廢棄本來的網址,那麼用戶並不知道這個事情,因此用戶仍是會訪問原來的網址,那麼就會內部作一個重定向到新啓用的網址,重定向的過程會有狀態碼的返回,搜索引擎捕捉到重定向的代碼,有利於搜索引擎優化。html

關鍵詞:重定向在設計上會提高用戶體驗 ,有利於搜索引擎優化前端

1.3 如何使用重定向?

首先從flask模塊中把導入redirectjava

from flask import Flask,redirect

1.3.1 暫時性重定向(代碼實例)

from flask import Flask,redirect
...
@app.route('/user_info/')
def user_info():
    name = request.args.get('name')
    pwd = request.args.get('pwd')
    if name=='mark' and pwd == '123':
        return '{}的信息'.format(name)
    return redirect('/login/')  # 能夠換成 return redirect(url_for('login'))


@app.route('/login/')
def login():
    return '這是登陸頁面'
...

沒有經過權限驗證的狀況python

經過權限驗證的狀況程序員

關鍵詞:暫時性重定向return redirect('/login/') 便可實現重定向flask

1.3.2 永久性重定向(代碼實例)

from flask import Flask,redirect
...
@app.route('/user_info/')
def user_info():
    name = request.args.get('name')
    pwd = request.args.get('pwd')
    if name=='mark' and pwd == '123':
        return '{}的信息'.format(name)
   return redirect('/login/', code=301)  # 會返回301狀態碼給瀏覽器 


@app.route('/login/')
def login():
    return '這是登陸頁面'
...

關鍵詞:永久性重定向只給redirect('/login/', code=301)多加了個code=301參數bootstrap

 

2 jinja2模板引擎

2.1 什麼是模板引擎?

實現視圖的業務邏輯和返回給前端的頁面邏輯分離的工具,咱們稱之爲模板引擎。瀏覽器

什麼是模板?

模板能夠理解爲一個特殊的html文件,特殊之處就在於這個html文件包含固定內容和動態部分,其動態部分能夠藉助模板引擎進行傳參

2.2 爲何要有模板引擎?

在上一章其實咱們已經應用過模板引擎,試想一下若是沒有模板引擎,直接給把模板的html代碼寫在視圖函數裏面,會給程序員的平常開發帶來了多大的困擾,模板引擎幫咱們分開了業務邏輯和頁面邏輯,而且咱們每次修改一個大字符串會很是不方便。模板引擎還能夠讀取並執行模板中的特殊語法標記,並根據傳入的數據將變量替換爲實際值,而後返回給瀏覽器,這個過程咱們稱之爲渲染。

關鍵字:完成了業務邏輯和頁面邏輯的分離,實現了動態的去渲染頁面。

2.3 在Flask如何使用模板引擎?

Flask使用jinja2做爲框架的默認模板引擎,Jinja2是基於python的模板引擎,功能比較相似於於PHPsmartyJ2eeFreemarkervelocityJinja2除了設置變量,還容許咱們在模板中添加if判斷,執行for迭代,調用函數等,以各類方式控制模板的輸出。而且jinja2不限制模板的格式爲html,能夠是任何格式的文本文件。

2.3.1 模板引擎返回對比視圖函數直接返回html代碼

項目目錄

項目代碼

(1)login01.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸界面</title>
</head>
<body>
<h1>login01</h1>  <!--login02.html文件的這一行的內容是:‘ <h1>login02</h1> ’  -->
<form action="" method="POST">
    用戶:<input type="text" name="username">
    密碼:<input type="text" name="password">
    <input type="submit" value="提交">
</form>
</body>
</html>

(2)login02.html

<meta charset="UTF-8">
    <title>登陸界面</title>
</head>
<body>
<h1>login01</h1>  <!--login02.html文件的這一行的內容是:‘ <h1>login02</h1> ’  -->
<form action="" method="POST">
    用戶:<input type="text" name="username">
    密碼:<input type="text" name="password">
    <input type="submit" value="提交">
</form>
</body>
</html>

(3) server.py

from flask import Flask, render_template
import config

app = Flask(__name__)
app.config.from_object(config)



@app.route('/demo/')
def demo():
    return '<h2>手寫html</h2>'

@app.route('/demo02/')
def demo02():
    return '''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸界面</title>
</head>
<body>
<!--<form action="/login_request/" method="POST">-->
<form action="" method="POST">
    用戶:<input type="text" name="username">
    密碼:<input type="text" name="password">
    <input type="submit" value="提交">
</form>
</body>
</html>'''

@app.route('/demo03/')
def demo03():
    return render_template('login01.html')

@app.route('/demo04/')
def demo04():
    return render_template('box/login02.html')


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

server.py代碼邏輯分析

  • demo函數 和 demo02函數證實直接返回html代碼可渲染瀏覽器
  • demo03 證實利用模板引擎 實現了業務邏輯和頁面邏輯的分離,減輕了開發的複雜度
  • demo04 證實了 render_template('box/login02.html')的路徑是templates文件夾的相對路徑

2.3.2 修改默認模板引擎尋找路徑

Flask類中的template_folder參數能夠指定模板尋找路徑

基於上2.3.1的項目

  1. 如今把templates中的文件複製到 C:/Users/Administrator/Desktop/template_box中,而且刪除項目中的templates的文件。
  2. 修改server.py中app = Flask(__name__)app = Flask(__name__,template_folder='C:/Users/Administrator/Desktop/template_box')

分析:

渲染一切正常 說明Flask類中的template_folder參數能夠指定模板尋找路徑。

2.3.3 模板引擎傳參

咱們以前提到過,模板引擎還能夠讀取並執行模板中的特殊語法標記,並根據傳入的數據將變量替換爲實際值,這個步驟咱們就稱之爲模板引擎傳參。

咱們傳參的時候要應用render_template()利用render_template的第二個參數進行傳參,該函數在定義時候,第二個參數是可變長形參,因此在傳值的時候咱們能夠傳入多個關鍵字實參。

在模板中接收的時候使用{{}}包裹參數進行接收。

 

實例1(第一種傳參方式):

目錄結構

Copy│ server.py
│
└─templates # 文件夾
        index.html

server.py

@app.route('/')
def index():

    return render_template('index.html',name="mark",age=18)

index.html

Copy<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板傳參</title>
</head>
<body>
    {{name}}
    {{age}}
</body>
</html>

實例2(第二種傳參方式):

目錄結構:同上

server.py

@app.route('/demo1/')
def demo1():
    context_dict = {"name":"mark",
               "age":"mark",
               "sex":"girl"}

    return render_template('index.html',context_dict = context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板傳參</title>
</head>
<body>
    {{context_dict.name}}
    {{context_dict.age}}
    {{context_dict.sex}}
</body>
</html>

實例3(第三種傳參方式):

目錄結構:同上

server.py

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>

關鍵詞:

在視圖函數中

  • render_template傳參的時候以關鍵字實參進行傳參。能夠傳多個,能夠用**講字典打散成關鍵字實參。

在模板中

  • jinja2模板引擎支持接收變量在用 {{}}包裹參數進行接收
  • 而且若是發現是字典,能夠用.字典裏面的key取出value值。也能夠直接字典跟[]進行取值。

2.3.4模板中使用url_for()

在模板中若是有使用url的需求,咱們能夠直接手寫一個url,也可使用{{ url_for('視圖函數名') }動態翻轉一個url。

實例:

項目目錄:

│ server.py
│
└─templates # 文件夾
        index.html
        info.html

server.py

...
@app.route('/')
def index():

    return render_template('index.html', name="mark", age=18)


@app.route('/info/')
def info():

    return render_template('info.html')
...

info.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>信息頁面</title>
</head>
<body>
    <h1>這是信息頁面</h1>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板傳參</title>
</head>
<body>
    <a href="/info/">正常跳轉</a>
    <a href="{{ url_for('info') }}">urlfor跳轉</a>
</body>
</html>

正常跳轉 和 urlfor跳轉,皆能夠實現跳轉到info.html頁面。

正常跳轉就不作演示了

關鍵詞:
  • url_for 在視圖函數中如何使用,在模板中一樣的用法。
  • 支持翻轉查詢字符串
  • 支持動態路由翻轉

2.3.5 jinja2中控制語句

在jinja2中用{% %}特殊符號來編輯控制語句,一個語句以{% ... %}爲起始 而且以{% end... %}來標記結束。

1 jinja2中邏輯語句/if語句

可使用> , < , <=, ==,!=,進行判斷,

也可使用 and,or,not,()來進行邏輯合併

{% if age > 18 %}
        <p>成年人</p>
    {% elif age == 18 %}
        <p>剛剛成年</p>
    {% else %}
        <p>未成年</p>
    {% endif %}

注意:<p>只是爲了渲染明顯

實例:

項目目錄

│ server.py
│
└─templates # 文件夾
        index.html

server.py

...
@app.route('/')
def hello_world():
    context_dict = {
        'age': 17,
        'sex': 'man',
    }
    return render_template('index.html',**context_dict)
...

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jinja2分支</title>
</head>
<body>
    {% if sex == 'man' %}
        <p>男人</p>
    {% else %}
        <p>女人</p>
    {% endif %}

    {% if age > 18 %}
        <p>成年人</p>
    {% elif age == 18 %}
        <p>剛剛成年</p>
    {% else %}
        <p>未成年</p>
    {% endif %}
</body>
</html>

2 jinja2中循環語句/for循環

for循環能夠便利任何一個可迭代對象,包括列表、字典等,支持反向遍歷

列表循環:

{% for country in countrys%}
        <p>{{ country }}</p>
    {% else %}
        <p>沒有值</p>
    {% endfor %}
2.1 列表循環遍歷項目實例:

項目目錄:

│ server.py
│
└─templates # 文件夾
        index.html

sever.py

@app.route('/')                                                
def hello_world():                                             
    context_dict = {                                           
        'countrys':["1-china","2-America","3-French"]          
    }                                                          
    return render_template('index.html',**context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>for循環</title>
</head>
<body>
    {% for country in countrys %}  {#    {% for country in countrys|reverse %} 能夠實現反向遍歷#}
        <p>{{ country }}</p>
    {% else %}
        <p>沒有值</p>
    {% endfor %}

</body>
</html>

反向遍歷實例

server.py`的 `{% for country in countrys %}` 改成 `{% for country in countrys|reverse %}

能夠實現反向遍歷,運行效果以下圖

2.2 字典循環遍歷項目實例:

項目目錄

│ server.py
│
└─templates # 文件夾
        index.html

sever.py

@app.route('/')                                         
def hello_world():                                      
    context_dict = {                                    
        'countrys':["1-china","2-America","3-French"]   
    }                                                   
    return render_template('index.html',**context_dict) 
                                                        
@app.route('/demo/')                                    
def demo():                                             
    context_dict ={                                     
        'colleges':[                                    
            {                                           
                'name': '清華大學',                         
                'area': '北京'                            
            },                                          
            {                                           
                'name': '復旦大學',                         
                'area': '上海'                            
                ''                                      
            },                                          
            {                                           
                'name': '吉林大學',                         
                'area': '吉林'                            
            },                                          
            {                                           
                                                        
                'name': '中山大學',                         
                'area': '廣東'                            
            }                                           
        ]                                               
    }                                                   
    return render_template('index.html',**context_dict)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>for循環</title>
</head>
<body>

    <table>
        <tr>
            <th>1開始的序號</th>
            <th>0開始的序號</th>
            <th>大學名稱</th>
            <th>所屬地區</th>
            <th>總數</th>

        </tr>
        {% for college in colleges %}
            {% if loop.first %}
                <tr style="background: blue">
            {% elif loop.last %}
                <tr style="background: yellow ">
            {% else %}
                <tr>
            {% endif %}
                <td>{{ loop.index }}</td>
                <td>{{ loop.index0 }}</td>
                <td>{{ college.name }}</td>
                <td>{{ college.area }}</td>
                <td>{{ loop.length }}</td>
            </tr>
        {% endfor %}
    </table>
    
</body>
</html>

for循環經常使用變量表

for循環經常使用變量 功能描述
loop.index 當前循環的索引(從1開始)
loop.index0 當前循環的索引(從0開始)
loop.first 是不是第一次循環,是返回True,不然返回Flase
loop.last 是不是最後一次循環,是返回True,不然返回Flase
loop.length 總共能夠循環的次數 / 迭代器的長度
for循環中的else用法

for還能夠else分支語法,若是for內部沒有遍歷出來內容,那麼就會走else分支,反之若是for循環遍歷出了內容,則不會運行else分支。

注意:jinja2中的forelse邏輯不通於python在此不要類比python中的 forelse

{% for country in countrys|reverse %}
        <p>{{ country }}</p>
    {% else %}
        <p>沒有值</p>
    {% endfor %}

2.3.6 模板加載靜態文件

在模板中加載靜態文件的時候也要使用到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

Copybody{
    background: red;
}

demo.js

Copyalert('hello world')

2.3.7 模板的繼承

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中的代碼:

子模板中:

Copy{% block main %}
    {{ self.demo() }} {# self.其餘block名字 #}
    <p>子模板中重寫main的內容 </p>
{% endblock %}

4 子模板中的想定義本身的代碼只能放到block中,不然無效

實例

注意:這裏面咱們使用了bootstrap框架。

bootstrap3的中文官網:https://v3.bootcss.com/

1 首先下載 用於生產環境的 Bootstrap

2 解壓出來裏面的css文件

項目目錄

Copy│  app.py
│
├─static  # 文件夾
│  └─css
│          bootstrap-theme.css
│          bootstrap-theme.css.map
│          bootstrap-theme.min.css
│          bootstrap-theme.min.css.map
│          bootstrap.css
│          bootstrap.css.map
│          bootstrap.min.css
│          bootstrap.min.css.map
│
├─templates  # 文件夾
       base.html
       detail.html

css文件夾: 是從咱們上面下載好的用於生產環境的 Bootstrap中解壓出來的

base.html 注意:裏面的form標籤中的內容和nav標籤中的內容均是bootstrap框架的代碼截取,div標籤是用於清除浮動

Copy<!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

Copy{% 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(TEMPLATES_AUTO_RELOAD=True)語句用於每次都從新加載模板文件

Copyfrom 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()

子模板運行效果

相關文章
相關標籤/搜索