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()
<!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>
<!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>
<!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>
版本二:認證裝飾器-基於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()
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)