Flask:初識(返回值、request、Jinjia2語法、session)


flask 初識

一、flask 中的 返回值

示例:一個簡單的 flask 項目的啟動

  該框架的返回值主要包括5類( 字符串、重定向、頁面、json數據、文件(圖片和視頻)等  )

from flask import Flask, redirect, render_template,json,jsonify,send_file

app = Flask(__name__)


@app.route("/")
def index():
    # return "hello"                 # 返回字符串直接返回即可
    return redirect("/login")      # 重定向


@app.route('/login',methods=["POST","GET"])   # 不寫methods,默認是GET請求, def home():
    return render_template('login.html')  # 返回html頁面,template設置為 mark derectory


@app.route('/json')
def jsons():
    l = {'name':'cheney'}
    # return json.dumps(l)      # 響應頭:Content-Type: text/html; charset=utf-8 ()
    return jsonify(l)        # 響應頭:Content-Type: application/json(返回json標准的字符串 )兩者是響應頭的區別,前端能夠識別


@app.route('/file')
def file():
    # return send_file('01.mp4')    # send_file(),打開文件並返回文件內容(自動識別文件格式)
    return send_file('22.png')    # 返回的是圖片,二進制文件時,背景是特殊顏色

app.run("0.0.0.0",5000,debug=True)      # 設置debug=True,修改代碼,項目可以不重啟,如果里面不寫參數,默認是127.0.0.1:5000端口的

二、flask 中的 request 

  request,是公共變量

from flask import request

request.method    # 請求方式 'POST' 'GET'

request.form      # 存放FormData中的數據 to_dict 序列化成字典("username":"chen","password":"123"),表單數據提交的都是formdata類型的
 
request.args      # 獲取URL中的數據 to_dict 序列化成字典 (get請求中的參數,問號之后的)

request.files     # 序列化文件存儲 save()

request.url       # 訪問的完整路徑  http://127.0.0.1:8000/login   有參數包括參數 ?a=1&b=2

request.path      # 路由地址  (/login)

request.host      # 主機地址   (127.0.0.1:8000)

request.values    # 獲取 FormData and URL中的數據,不要用to_dict,會覆蓋

request.json      # 如果提交時請求頭中的Content-Type:application/json 字典操作

request.data      # 如果提交時請求頭中的Content-Type 無法被識別 將請求體中的原始數據存放 byte

request.cookies   # 獲取Cookie中的數據

request.headers   # 獲取請求頭

 

文件的保存:

my_file = request.files.get("my_file")
my_file.save(my_file.filename)   # 可以用原文件的名字,也可以用自己定義的名字和路徑,'./chen',當前路徑

 

三、Jinja2 語法

flask 中的 Jinja2 類似於 django 中的模板語法(template),兩者做的事情是一樣的,都是將后端傳的內容在前端頁面進行渲染

不同的是:

  Jinjia2 用法類似python,取值符合字典列表的規則

  template 用法都是用點 . 取值

1、變量的取值

  {{  }}

    取值類似字典,{{ stu.name }} 、{{ stu[name] }}、{{ stu.get(name) }} 都可以獲取值,django中模板語法只能用 點 取值

2、邏輯代碼

  {%  %}

3、渲染標簽,安全標簽字符串

  標簽字符串 | safe

  Markup()

4、全局的

  @app.template_global()

5、過濾的

  @app.template_filter()

6、宏 macro 用處不大,定義函數,了解即可

 

示例: 

  后端  ss.py

from flask import Flask, render_template, Markup

app = Flask(__name__)

tag = "<input type='text' name='username'>"
tag = Markup(tag)           # 類似於django中的 Marksafe(),這里用了,前端就不用 tag|safe  了


def func1(a, b):
    return a + b


@app.template_global()
def func(a, b):         # 類似func1,如果多個頁面中都要用到func函數,那么就需要每個路由函數都傳值函數名,比較麻煩,
                        # 因此使用,template_global()即可,設為全局的
    return a + b


@app.template_filter()
def filter(a, b, c):    # 過濾器函數,template_filter(),也是全局的,不需要傳值,模板中直接用即可
    print(a)
    return a + b + c


@app.route("/")
def index():
    return render_template("index2.html", tag=tag, func1=func1)     # func1不是全局的,需要傳值


app.run(debug=True)

 

  前端   index2.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body> {{ tag }} {{ func1(3,3) }} {{ func(5,5) }} {{ 10 | filter(2,3) }}

{% macro create_input(na,ty) %}
    {{ na }} : <input type="{{ ty }}" name="{{ na }}">
{% endmacro %}
{{ create_input("username","text") }}

</body>
</html>

四、flask 中的 session(利用裝飾器驗證登錄)

1、裝飾器的用法

  裝飾器主要是用於對某些程序在運行執行做一些處理操作,

  示例:利用裝飾器,計算程序運行的時間 

import time


def waibu(func):
    def neibu(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return ret

    return neibu


@waibu
def func():
    for i in range(100000000):
        continue
    return "OK"


print(func())  # 1.7812395095825195    # OK

 

2、Flask-Session

  session也是公共變量

  session是用於驗證用戶身份信息的,可以在登錄的時候添加session,訪問其他頁面的時候校驗用戶身份信息。

    django:session是存儲在服務端的,

    flask:session是加密后存儲在前端的cookies中的鍵值對,節省flask的開銷,

       由於Flask中默認Session 存放位置 - 客戶端的Cookies中,加密使用 app.secret_key = "加密字符串" ,加密字符串可以隨便寫,主要是用於序列化和反序列化 session信息,

  • 有人說,session放在前端cookies中,會不完全?

    由於在加密的時候,該加密方式是添加了字符串的,再進行加密,而字符串是保存在后端的,因此,別人不知道字符串自然也無法解密

  • 請求進入視圖函數 帶上cookie 將Session從cookie序列化出來 通過secret_key 反序列化成字典

xxx.py

from flask import Flask, redirect, render_template, request, session

app = Flask(__name__)
app.secret_key = "DragonFire"  # 這里一定要給定字符串,進行加密

@app.route("/login", methods=["POST", "GET"])    # 在涉及到其他請求的時候,一定要添加進來,不寫則請求不能訪問,默認是GET,如果只有GET訪問的話可以不寫 def login():
    if request.method == "GET":
        return render_template("login.html")

    if request.form.get("username") == "chen" and request.form.get("password") == "123":
        session["user"] = request.form.get("username")   # 登錄成功,將用戶信息添加到session中 ,訪問其他路由的時候,通過session進行驗證即可。

       return redirect("/")


app.run(debug=True)

 login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
  用戶名<input type="text" name="username">
  密碼<input type="password" name="password">
  文件:<input type="file" name="my_file">
  <input type="submit" value="登錄">
</form>
</body>
</html>
View Code

 

3、利用裝飾器驗證session,進行用戶登錄

  示例:

from flask import Flask, redirect, render_template, request, session

app = Flask(__name__)
app.secret_key = "DragonFire"


@app.route("/login", methods=["POST", "GET"])  # 登錄不能加裝飾器,驗證session
def login():
    if request.method == "GET":
        return render_template("login.html")

    if request.form.get("username") == "chen" and request.form.get("password") == "123":
        session["user"] = request.form.get("username")
        print(session['user'])
        print(11)

        return redirect("/index")


def wai(func):                        # 驗證session信息的裝飾器函數
    def nei(*args, **kwargs):
        if session.get("user"):            # session取值,不要使用所以["user"]取值,因為不確定時候有鍵,沒有會報key-error錯誤
            ret = func(*args, **kwargs)
            return ret
        else:
            return redirect("/login")

    return nei


@app.route("/",methods=['GET'],endpoint='hello')   # 不指定endpoint的函數名,會報錯,裝飾器不能使用,另外裝飾器(@wai)要放在下面
@wai                                                # nei = wai(hello) def hello():
    return  'hello'


@app.route("/index",methods=['GET'],endpoint='index')
@wai                                               # nei = wai(index) def index():
    # if not session.get("user"):        # 可以再每個函數中進行session身份信息的驗證,但是比較麻煩,會有代碼的重復
    #     return redirect("/login")
    return render_template("index.html")


app.run(debug=True)

   總結:

    1、裝飾器函數修飾要放在@app.route() 的下面

    2、使用裝飾器@wai,沒有在@app.route()中指明 endpoint的路由函數,裝飾器是不能使用的,會報一下錯誤

        AssertionError: View function mapping is overwriting an existing endpoint function: nei

      為什么會出現這種問題?

使用Flask定義URL的時候,如果出現"AssertionError: View function mapping is overwriting an existing endpoint function"這個異常信息,就說明定義了多個同名的視圖函數,只需要改成不同的函數名即可。
這是為什么呢?

原來flask中url跟視圖函數並不是直接對應的,而是有一個中間者-endpoint。

三者之間的關系是這樣的:

```
url---->endpoint---->view_function
```

它們是一對一的關系,在注冊add_url_rule的時候,如果不指定endpoint,那么endpoint就會默認為函數名字,如果同一個endpoint於多個url注冊的話,就會發生沖突,從而拋出異常。

     3、解決辦法就是:在route中指明 endpoint="路由函數名"

      方式一:在route中指明 endpoint="路由函數名",上面的示例采用的是該方式

                           

        源碼中解析:

           如果不指定endpoint,那么會默認是傳入@app裝飾器的原函數,這里也就是@wai 裝飾后的函數名 nei,多個函數都裝飾的時候就會重復,所以會報錯

       

 

       方式二、利用functools保持原來的函數名

         

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM