Flask

Python 現階段三大主流Web框架 Django Tornado Flask 對比:html

  Django 主要特色是大而全,集成了不少組件,例如: Models Admin Form 等等, 無論你用獲得用不到,反正它全都有,屬於全能型框架
  Flask 主要特色小而輕,原生組件幾乎爲0, 三方提供的組件請參考Django 很是全面,屬於短小精悍型框架
  Tornado 優勢是異步,用於遊戲服務後臺,缺點是乾淨,連個Session都不支持前端

  flask和django最大的不一樣點:request/session 是須要單獨導入的python

 

flask知識點:mysql

  - 模板+靜態文件,app= Flask(__name__,....)
  - 路由 
    @app.route('/index',methods=["GET"])
  - 請求 
    request.form
    request.args
    request.method
  -響應

    render
    redirect
  -session

    session['xx'] = 123
    session.get('xx')

Flask初級實現:sql

from flask import Flask   #Flask是個類

#傳參實例化Flask,拿到一個對象app
app = Flask(__name__)

@app.route('/index')  #路由和下面函數綁定,@後面寫上面實例化對象的名字
#寫一個函數,return一個結果
def index():
    return "hello word-flask"

#調用裏面的run方法
app.run()

 優化爲:django

from flask import Flask   #Flask是個類

#傳參實例化Flask,拿到一個對象app
app = Flask(__name__)

@app.route('/index')  #路由和下面函數綁定,@後面寫上面實例化對象的名字
#寫一個函數,return一個結果
def index():
    return "hello word-flask"

#調用裏面的run方法
if __name__ == '__main__':
    app.run()

知識點一:用到的知識點有rsplit::切分 、getattr:返回對象屬性值 、dir:返回模塊的屬性列表json

經過給定一個字符串路徑,找到對應的類及類裏面的屬性和屬性值flask

例如:- 給你一個路徑 「settings.Foo」,能夠找到類並獲取去其中的大寫的靜態字段。後端

test.py裏面的設置瀏覽器

import importlib

path = 'settings.Foo'
p,c =path.rsplit('.',maxsplit=2)  #maxsplit表明切分幾回
# print(p,c) #settings Foo
#拿到settings所在的路徑
m=importlib.import_module(p) #<module 'settings' from 'E:\\知識點練習\\知識點回憶\\settings.py'>

#getattr返回對象屬性值
cls=getattr(m,c)
print(cls) #<class 'settings.Foo'>

"""例以下面:
>>>class A(object):
...     bar = 1
... 
>>> a = A()
>>> getattr(a, 'bar')        # 獲取屬性 bar 值

"""
#如何找到這個類
#dir() 函數不帶參數時,返回當前範圍內的變量、方法和定義的類型列表;帶參數時,返回參數的屬性、方法列表。
# print(dir(cls)) #['DEBUG', '__class__', '__delattr__',...]
for key in dir(cls):
    if key.isupper():
        #DEBUG True 最終拿到類中屬性及屬性值
        print(key,getattr(cls,key))
根據字符路徑找內容

配置文件:查看、修改

settings.py設置:設置配置文件參數

#經過settings文件,完成對app.config配置文件的修改
#分類,方便app裏面不一樣的應用場景調用

#共同須要的配置寫在基類裏面,下面單獨修改的部分去繼承這個基類
class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'

# 開發環境
class DevelopmentConfig(Config):
    DEBUG = True


#上線環境
class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'


class TestingConfig(Config):
    TESTING = True

app.py配置:引用settings配置文件,實現查看、修改

from flask import Flask,render_template,redirect,request

app=Flask(__name__)

#查看配置文件
print(app.config)

#修改配置文件
#方式一:單獨修改一項
# app.config['DEBUG'] = True

#方式二:批量修改,from_object後面是個字符串(根據字符串找到settings類,在類裏面統一去作一些修改)
app.config.from_object("settings.DevelopmentConfig")  #根據需求調用settings配置文件裏面的類

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

路由系統:

首先,要導入url_for: from flask import url_for

近而,經過url_for反向生成url地址

靜態路由:無參數、反向解析endpoint

@app.route('/index/123/456',methods=['GET','POST'],endpoint='n1')  #endpoint='n1'相似於Django裏面的name,用於反向解析
def index():
    # 經過url_for 反向生成url
    print(url_for('n1'))  #/index/123/456
    # 若是不指定endpoint='n1',默認寫路由對應裝飾的函數的名字
    print(url_for('index')) #/index/123/456
    
     user=session.get('user')
    # print(session)  session相似個字典(裏面包含的用戶名信息):    
    <SecureCookieSession {'user': 'yzz'}>
    if not user:
        return redirect('/login')
    return render_template('index.html')

 

動態路由:有參數、也能夠搭配反向解析使用

#動態路由(<int:nid>)index要接收nid
@app.route('/index/<int:nid>', methods=['GET', 'POST'])  # endpoint='n1'相似於Django裏面的name,用於反向解析
def index(nid):
    print(nid) #拿到的時你實際瀏覽器輸入的值
    #url_for 有參數就傳參數,沒參數就寫endpoint的值
    print(url_for('index',nid=733)) #/index/733

    user=session.get('user')
    # print(session)  session相似個字典(裏面包含的用戶名信息):<SecureCookieSession {'user': 'yzz'}>
    if not user:
        return redirect('/login')
    return render_template('index.html')

FBV:

請求與響應:

#請求與響應
# 請求相關信息
        request.method
        request.args
        request.form
        request.values
        request.cookies
        request.headers
        request.path
        request.full_path
        request.script_root
        request.url
        request.base_url
        request.url_root
        request.host_url
        request.host
        request.files
        obj = request.files['the_file_name']
        obj.save('/var/www/uploads/' + secure_filename(f.filename))

# 響應:
        # 響應體:
        第一種:return 「asdf」
        第二種:return jsonify({'k1': 'v1'})  #jsonify將字典轉爲字符串返回
        第三種:return render_template('xxx.html')
        第四種:return redirect()


        # 定製響應頭:例如第一種方式
        obj = make_response("asdf")  #設置個響應體
        obj.headers['xxxxxxx'] = '123'  #設置個響應頭 響應頭裏面會增長一項:xxxxxxx:123
        obj.set_cookie('key', 'value')   #設置cookies 響應頭裏面會增長一項:Set-Cookie:key=value; Path=/
        return obj

實例:

版本一:學生管理-簡單登陸、刪除、查看

from flask import Flask
#導入三大組件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默認後臺文件夾的名字

#須要加鹽(由於flask的session是放在本地cookie裏面的,只不過是加密),也能夠添加在app.settings配置裏面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根據需求調用settings配置文件裏面的類


STUDENT_DICT = {
    1:{'name':'張三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}

#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用戶名或密碼錯誤')


#靜態路由(無參數)
@app.route('/index')
def index():
    user = session.get('user')

    if not user:
        return redirect('/login')
    return render_template('index.html',stu_dic=STUDENT_DICT)

@app.route('/delete/<int:nid>')  #接收前端點擊,對應的nid,戰隊nid進行刪除
def delete(nid):
    user = session.get('user')

    if not user:
        # return redirect('/login')
        return redirect(url_for('login'))

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))

@app.route('/detail/<int:nid>')
def detail(nid):
    user = session.get('user')

    if not user:
        return redirect('/login')
    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)


if __name__ == '__main__':

    app.run()
主文件app.py
<!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>
    <h1>用戶登陸</h1>
    <form method="post">
        <input type="text" name="user">
        <input type="password" name="pwd">
        <input type="submit" value="提交">{{error}}
    </form>
</body>
</html>
登陸lgin.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>
    <h1>學生列表</h1>
    <table border="1px">
        <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>年齡</th>
                <th>性別</th>
                <th>選項</th>
            </tr>
        </thead>

        <tbody>
            {% for k,v in stu_dic.items()%}
                <tr>
                    <td>{{k}}</td>
                    <td>{{v.name}}</td>
                    <td>{{v.age}}</td>
                    <td>{{v.gender}}</td>
                    <td>
                        <a href="/detail/{{k}}">查看詳情</a> |
                        <a href="/delete/{{k}}">刪除</a>
                    </td>


                </tr>
            {%endfor%}
        </tbody>



    </table>

</body>
</html>
學生信息一覽index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>學生詳情</title>
</head>
<body>
    {% for item in info.values()%}
        <li>{{item}}</li>
    {%endfor%}

</body>
</html>
單個學生詳情detail.html

版本二:認證裝飾器-基於functools模塊(應用於比較少的函數中須要額外添加功能)

from flask import Flask
#導入三大組件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默認後臺文件夾的名字

#須要加鹽(由於flask的session是放在本地cookie裏面的,只不過是加密),也能夠添加在app.settings配置裏面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根據需求調用settings配置文件裏面的類


STUDENT_DICT = {
    1:{'name':'張三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}

#登陸認證裝飾器
import functools
def auth(func):
    @functools.wraps(func)
    def innder(*args,**kwargs):
        if not session.get('user'):
            return redirect(url_for('login'))
        ret = func(*args,**kwargs)
        return ret
    return innder


#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用戶名或密碼錯誤')


#靜態路由(無參數)
@app.route('/index')
@auth
def index():

    return render_template('index.html',stu_dic=STUDENT_DICT)
print(index.__name__)

@app.route('/delete/<int:nid>')  #接收前端點擊,對應的nid,戰隊nid進行刪除
@auth
def delete(nid):

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))
print(delete.__name__)

@app.route('/detail/<int:nid>')
@auth
def detail(nid):

    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)
print(detail.__name__)

if __name__ == '__main__':

    app.run()

版本三:認證裝飾器-基於@app.before_request(應用於須要裝飾的方法較多時)

@app.before_request
def xxxx():
    if request.path == '/login':
        return None   #return None,表示容許經過,繼續顯示相應頁面
    if session.get('user'):
        return None

    return redirect('/login')
from flask import Flask
#導入三大組件:render_template模板渲染  redirect重定向
from flask import render_template,request,redirect,session,url_for,jsonify,make_response

app = Flask(__name__,template_folder="templates",static_folder="static") #默認後臺文件夾的名字

#須要加鹽(由於flask的session是放在本地cookie裏面的,只不過是加密),也能夠添加在app.settings配置裏面
app.secret_key = 'fjsjflks'

# 修改配置文件
app.config.from_object("settings.DevelopmentConfig")  #根據需求調用settings配置文件裏面的類


STUDENT_DICT = {
    1:{'name':'張三','age':12,'gender':''},
    2:{'name': '李四', 'age': 34, 'gender': ''},
    3:{'name': '王五', 'age': 45, 'gender': ''},
}


@app.before_request
def xxxx():
    if request.path == '/login':
        return None   #return None,表示容許經過,繼續顯示相應頁面
    if session.get('user'):
        return None

    return redirect('/login')


#路由配置
@app.route('/login',methods=['GET','POST'])
def login():
    if request.method=="GET":
        # return 'login'
        return render_template('login.html')

    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'yzz' and pwd == '123':
        session['user'] = user
        return redirect('/index')

    return render_template('login.html', error='用戶名或密碼錯誤')


#靜態路由(無參數)
@app.route('/index')
def index():

    return render_template('index.html',stu_dic=STUDENT_DICT)


@app.route('/delete/<int:nid>')  #接收前端點擊,對應的nid,戰隊nid進行刪除
def delete(nid):

    del STUDENT_DICT[nid]
    return redirect(url_for('index'))


@app.route('/detail/<int:nid>')
def detail(nid):

    info = STUDENT_DICT[nid]
    return render_template('detail.html',info=info)


if __name__ == '__main__':

    app.run()
app.py詳細配置

 

Flask中的三劍客:Render_template Redirect HttpResponse:

  HttpResponse:就是直接返回字符串

  Redirect:網頁跳轉重定向

  Render_template:使用時須要再主目錄中加入一個templates 目錄(不然會報一個jinjia2...的異常)

 

Request:

注意點:

  1.解釋一個 @app.route("/req",methods=["POST"]) :
    methods=["POST"] 表明這個url地址只容許 POST 請求,是個列表也就是意味着能夠容許多重請求方式,例如GET之類的
  2.Form表單中傳遞過來的值 使用 request.form 中拿到
  3.Flask 的 request 中給咱們提供了一個 method 屬性裏面保存的就是前端的請求的方式

  4.request.args 與 request.form 的區別就是:
    request.args:是獲取url中的參數
    request.form :是獲取form表單中的參數
  5.request.values :只要是個參數我都要

  6.reuquest.cookies:將cookie信息讀取出來

  7.request.headers:拿出請求頭中的的祕密

  8.request.files:拿到的是你上傳的文件

  9. request.json 之 前提你得告訴是json

   若是在請求中寫入了 "application/json" 使用 request.json 則返回json解析數據, 不然返回 None

request.files:

html配置:
<form method="post" action="" enctype="multipart/form-data"> #注意上傳文件要配置enctype

    <p>用戶名<input type="text" name="username"></p>
    <p>用戶名<input type="password" name="password"></p>
    <p><input type="file" name="file"></p>
    <p><input type="submit" value="提交"></p>
    <p>
         {{ msg }}
    </p>


</form>

打印輸出:
print(request.files)
驗證結果:
ImmutableMultiDict([('file', <FileStorage: '011.docx' ('application/vnd.openxmlformats-officedocument.wordprocessingml.document')>)])

上面request其餘的驗證:

from flask import Flask,render_template,redirect,request
app=Flask(__name__)

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

    print(request.args) #ImmutableMultiDict([('id', '1'), ('age', '30')])
    return "Hello Flask,Welcome you"


@app.route("/login",methods=("POST","GET"))
def login():
    if request.method == "POST":

        # 它看起來像是的Dict
        print(request.form)  #ImmutableMultiDict([('username', 'yzz'), ('password', 'yzz')])
        # print(request.form.keys())  #<dict_keyiterator object at 0x042FF5A0>
        # print(list(request.form.keys())) #['username', 'password']


        username=request.form.get('username') #yzz
        password=request.form.get('password')
        if username == 'yzz' and password == 'yzz':
            return redirect('/index')
        else:
            return render_template("template.html",msg="密碼錯誤")

    return render_template("template.html", msg=None)
app.run(debug=True)

 

模板渲染:

查看學生信息:就向後端傳入字典、列表(套字典)、字典(套字典)

from flask import Flask,render_template,redirect,request
app=Flask(__name__)

#格式一
STUDENT = {'name': 'Old', 'age': 38, 'gender': ''},

'''
templates設置:
return render_template("stu.html",student=STUDENT)
路由函數設置:
{{student}}

'''

#格式二
STUDENT_LIST = [
    {'name': 'Old', 'age': 38, 'gender': ''},
    {'name': 'Boy', 'age': 73, 'gender': ''},
    {'name': 'EDU', 'age': 84, 'gender': ''}
]

'''
templates設置:
<table border="1xp">
        {% for foo in student %}
            <tr>
                <td>{{ foo.name }}</td>
                <td>{{ foo.get("age") }}</td>
                <td>{{ foo["gender"] }}</td>
            </tr>
        {% endfor %}
</table>

路由函數設置:
return render_template("stu.html",student=STUDENT_LIST)

'''

#格式三
STUDENT_DICT = {
    1: {'name': 'Old', 'age': 38, 'gender': ''},
    2: {'name': 'Boy', 'age': 73, 'gender': ''},
    3: {'name': 'EDU', 'age': 84, 'gender': ''},
}
'''
templates設置:
<table border="1xp">
        {% for k,v in student.items() %}
            <tr>
                <td>{{ v.name }}</td>
                <td>{{ v.get("age") }}</td>
                <td>{{ v["gender"] }}</td>
            </tr>
        {% endfor %}
</table>
路由函數設置:
return render_template("stu.html",student=STUDENT_DICT)

'''

 return_template也能夠傳遞多個值:

@app.route("/allstudent")
def all_student():
    return render_template("all_student.html", student=STUDENT ,
                           student_list = STUDENT_LIST,
                           student_dict= STUDENT_DICT)

 

Jinja2中的safe用法(xss攻擊有關,如何顯示html代碼讓瀏覽器識別定執行),結果輸出就不是字符串,而是執行後的網頁渲染效果

正常網頁顯示結果:

  <input type='text' name='user' value='DragonFire'>  #普通字符串格式

 

爲了讓瀏覽器可以識別並執行這個html代碼,能夠經過如下2中方式實現;

方式一:前端加safe實現

<body>
    <!--方式一:-->
    {{ tag | safe }}
</body>

方式二;後端導入Markup,實現

from flask import Markup

@app.route("/index")
def index():
    #方式二:
    #導入Markup
    from flask import Markup
    tag = "<input type='text' name='user' value='DragonFire'>" markup_tag=Markup(tag) print(markup_tag,type(markup_tag)) #<input type='text' name='user' value='DragonFire'> <class 'markupsafe.Markup'>

    return render_template("index.html", tag=markup_tag)
相關文章
相關標籤/搜索