flask基礎之一
hello world
#從flask這個包中導入Flask這個類
#Flask這個類是項目的核心,以後的很多操作都是基於這個類的對象
#註冊url,註冊藍圖都是這個類的對象
from flask import Flask
#創建一個Flask對象,傳遞__name__這個參數進去
#__name__這個參數的作用:
# 1.規定模板和靜態資源的路徑
# 2.以後的一些Flask插件,比如Flask_migrate,Flask_SQLAlchemy報錯的話,哪麼Flask就會通過這個參數找到具體的報錯位置
app = Flask(__name__)
# @app.route()是一個裝飾器,將對應的“/”路徑應用到hello_world()這個函數上面
# 在訪問“/”的時候在頁面上返回Hello World
@app.route('/')
def hello_world():
return 'Hello World!'
# 如果作爲一個主文件運行,哪麼執行app.run()方法,也就是啓動這個網站
if __name__ == '__main__':
app.run()**strong text**
debug模式
- 爲什麼要開啓DEBUG模式?
- 如果開啓了debug模式,name代碼在調試過程中出現了異常,在瀏覽器頁面中可以看到具體的報錯信息,以及具體的錯誤代碼位置,方便開發者調試。
- 如果flask開啓了debug模式,name以後再python中修改任何代碼,只要在pycharm中使用ctrl+s即可保存重載,不需要手動去重載程序
- 如何配置debug模式:
- app.run()
app.run(debug=True)
- app.debug
app.debug = True
- 配置信息方式(使用參數形式的方式)
app.config.update[DEBUG=True] #其實也就是update了config字典
- 通過配置文件的形式
- app.run()
- 創建一個config.py的配置文件,寫入
DEBUG = True - 然後在你的app.py文件中寫入
app.config.from_object(config) #即可讀取配置文件中的DEBUG=True**debug PIN碼** ``` python D:\MyDevSoftInstallDir\Python3\python3.exe D:/myflask/base/base.py
- Restarting with stat
- Debugger is active!
- Debugger PIN: 177-952-649
- Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
然後在頁面上調試代碼的時候用到。 也是爲了安全考慮。 ## 配置文件兩種方式詳解
- 第一種方式:
在項目主路徑下創建config.py
DEBUG=True
然後在主項目裏面去讀取
config.py
裏面的配置:from flask import Flask import config app = Flask(__name__) app.config.from_object(config)
- 第二種方式:直接讀取文件的形式,也可以是普通的txt文件形式;這種方式不需要直接
import config
在項目主路徑下創建config.py
DEBUG=True
然後在主項目裏面去讀取
config.py
裏面的配置:from flask import Flask app = Flask(__name__) app.config.from_pyfile('config.py',silent=True) #靜默模式加載配置文件(找不到配置文件不報錯),文件的後綴名不可少
url與視圖函數的映射
- 傳遞參數:
傳遞參數的語法是
/<參數類型:參數名稱>/
,然後在視圖函數中也要定義同名的參數 - 參數的數據類型
- string:只接受字符串,沒有任何“/或者\”的文本
- int:只接受整數
- float:只接受浮點數,整數都不行哈
- path:和
string
類似,但是接受斜槓 - uuid:只有接受符合
uuid
的字符赤岸,一般用作表的主鍵 - any:可以指定多種路徑
接收用戶傳遞參數的方式:
- 使用path的方式(將參數嵌入到路徑中)
- 使用查詢字符串的形式 (也就是通過
?key=value
的形式傳遞的,只能通過request.args.get的方式來獲取)
如果頁面想要做SEO優化的話,那麼推薦使用path
的形式,反之就是查詢字符串的形式
練習from flask import Flask,request app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' @app.route('/list/') def article_list(): return 'article list!' @app.route('/p1/<article_id1>') def article_detail(article_id1): return "請求的文章是:%s" %article_id1 @app.route('/p2/<string:article_id2>') def article_detail2(article_id2): return "請求的文章是:%s" %article_id2 @app.route('/p3/<int:article_id3>') def article_detail3(article_id3): return "請求的文章是:%s" %article_id3 @app.route('/p4/<path:article_id4>') def article_detail4(article_id4): return "請求的文章是:%s" %article_id4 # import uuid # print(uuid.uuid4()) @app.route('/p5/<uuid:article_id5>') #數據的唯一性,長度較長,有損效率(一般在用戶表中使用)6a9221f6-afea-424a-a324-8ceaa5bdfc98 def article_detail5(article_id5): return "請求的文章是:%s" %article_id5 @app.route('/p6/<any(blog,user):url_path>/<id>/') def detail(url_path,id): if url_path == "blog": return "博客詳情 %s" %id else: return "用戶詳情 %s" %id #通過問號形式傳遞參數 @app.route('/d/') def d(): wd = request.args.get('wd') #獲取瀏覽器傳遞參數 return '通過查詢字符串的方式傳遞的參數是,%s'%wd #請求http://127.0.0.1:8080/d/?wd=php if __name__ == '__main__': app.run(debug=True,host='0.0.0.0',port=8080)
url_for
- 將視圖函數反轉回URL,跟app.route相反
- URL的更新大於視圖函數,所以在大規模項目中比較實用
* 基本使用 : url_for
的第一個參數是視圖函數的函數名對應的字符串(endpoint),後面的參數就是你傳遞給url
;如果傳遞的參數在url
中已經定義了,那麼這個參數就會被當成path的值傳遞給url
;如果這個參數沒有在url
中定義,那麼將變成查詢字符串的形式from flask import Flask,url_for,request app.route('/') return url_for('my_list',page=1,count=2) #這樣的話就會在頁面上構建出/post/list/1/?count=2的信息 app.route('/post/list/<page>/') def my_list(): return 'my list'
- 爲什麼需要
url_for
?如果將來要修改
URL
,但沒有修改URL
對應的函數名,就不用到處去替換URL了。URL
會自動處理特殊字符(轉義成十六進制),不需要手動去處理from flask import Flask,url_for,request @app.route('/') def hello_world(): return url_for('login',next='/current') #頁面返回/login/?next=%2Fcurrent登錄前的信息 # print(url_for('my_list',page=1,count=200)) # return 'hello world' @app.route('/login/') def login(): # next = request.args.get('next') #登錄前的信息,在登陸之後仍舊保持 return 'login' @app.route('/list/<page>') def my_list(): return 'my list' @app.route('/detail/<id>/') def detail(): return 'detail' if __name__ == '__main__': app.run(debug=True)
自定義url轉換器
- url的參數轉換成滿足自己需求的數據類型
自定義url
轉換器的方式:- 實現一個類,繼承
BaseConverter
- 在自定義的類中重寫
regex
,也就是這個變量的正則表達式 - 將自定義的類映射到
app.url_map.converters
上。
實現用戶訪問/posts/a+bto_python
的作用
這個方法的返回值會傳到view函數中作爲參數to_url
的作用
這個方法的返回值會調用url_for來生成符合要求的url形式from flask import Flask,url_for from werkzeug.routing import BaseConverter app = Flask(__name__) #手機號碼正則 class TelephoneConveter(BaseConverter): regex = r'1[85734]\d{9}' app.url_map.converters['tel'] = TelephoneConveter #用戶訪問/posts/a+b/ class ListConverter(BaseConverter): def to_python(self, value): return value.split("+") def to_url(self, value): print(value) return '+'.join(value) # return "hello" app.url_map.converters['list'] = ListConverter @app.route('/') def hello_world(): print(url_for('posts',broads=['a','b'])) return 'Hello World!' @app.route('/user/<int:user_id>/') def user(user_id): return "your user id is %d" %user_id @app.route('/telephone/<tel:my_tel>/') def my_tel(my_tel): return "your telephone number is %s"%my_tel @app.route('/posts/<list:broads>/') def posts(broads): # broads = broads.split("+") return "your posts is %s"%broads if __name__ == '__main__': app.run(debug=True)
小細節
在局域網訪問站點
app.run(host='0.0.0.0')
指定端口號
默認是5000端口,修改端口如下
app.run(host='0.0.0.0',port=8899 )
ulr唯一
- 實現一個類,繼承
- 在定義
URL
的時候,儘量在url後面加/
,原因如下:- 如果不加
/
的話瀏覽器訪問這個url的時候會默認加/
,這樣的話就訪問不到了 - 搜索引擎會將不加
/
的url和加/
的url是兩個不同的url,會將其誤解。
###GET和POST請求
在網絡請求中有許多的請求方式,比如GET
,POST
,DELETE
,PUT
,常用的請求方式如下:
- 如果不加
GET
:也就是獲取
服務器上的資源,不會修改服務器上的內容。POST
:就是向服務器提交文件或者數據,一般POST會對服務器的狀態產生影響。- 關於參數傳遞:
GET
:把參數放到URL
中,通過?xx=xxx
的形式傳遞的,因爲會把參數放到url中,所以視力好的話,一眼就可以看到傳遞的參數。POST
:把參數放到Form Data
中,避免被偷窺到的風險(也有可能通過抓包的方式被竊取),一般不安全的,不曉得提交的內容是否是帶病毒的文件。在
flask
中,route
方法,默認只能使用GET
的方式請求url。如果想要設置自己的請求方式,那就要在methods
中多傳遞一個請求方式的參數。
實例如下:
創建url_detail的項目,項目結構如下:├─url_detail.py ├─static └─templates |_login.html
- url_detail.py"
from flask import Flask,request,render_template app = Flask(__name__) @app.route('/',methods=['GET']) def hello_world(): return 'Hello World!' @app.route('/list/',methods=['POST']) def my_list(): return 'list' @app.route('/login/',methods=["POST","GET"]) def login(): if request.method == 'GET': return render_template('login.html') else: return "Success" if __name__ == '__main__': app.run(debug=True,host='0.0.0.0')
- templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="",method="POST"> <input type="text",name="username"> <input type="text",name="password"> <input type="submit",name="submmit"> </form> </body> </html>
URL重定向
也就是從一個頁面跳轉到另一個頁面,也就是重新定位一個方向
分類: - 永久性重定向:http的狀態碼是301,多用於舊的網址廢棄了要轉到一個新的網址,確保用戶的訪問。最經典的就是
jingdong.com
了 - 暫時性重定向:http的狀態碼是302,表示頁面暫時性被跳轉,比如訪問一個需要權限的網址,如果當前用戶沒有登錄,應該重定向到登錄頁面。這種情況的話就是用暫時性重定向。
在flask中,重定向是通過
flask.redirect(location,code=302)
這個函數來實現的,location
指的是需要重定向到的URL
,應該配合之前講過的url_for()
來是用。code
代表的是什麼類型的重定向,默認是302,可以修改成301實現永久重定向。 - 小例子:
from flask import Flask,url_for,redirect,request app = Flask(__name__) app.debug = True @app.route('/login/',methods=['GET','POST']) def login(): return 'login page' @app.route('/profile/',methods=['GET','POST']) def profile(): name = request.args.get('name') if not name: return redirect(url_for('login')) else: return name if __name__ == '__main__': app.run()
這樣的話就能訪問profile了:
http://127.0.0.1:5000/profile/?name=sss
關於響應
視圖函數的返回值會被自動轉換成一個響應對象,flask的轉換邏輯如下:
- 如果返回的是一個合法的響應對象,則直接返回
- 如果返回的是一個字符串,那麼flask會重新創建一個
werkzeug.wrappers.Response
對象。Response
會將該字符串作爲主體,狀態碼爲200,MIME
的類型爲text/html
,然後返回給Response對象 - 如果返回的是一個元組,元組中的數據類型是
response,status,headers
,status會覆蓋默認的200狀態碼,headers可以是一個字典或者列表。作爲額外的消息頭 - 如果以上的條件都不滿足,flask會假設返回值是一個合法的
WSGI
應用程序,並通過Response.force_type(rv,request.environ)
轉換成一個請求對象。 - 自定義響應:
- 必須繼承自
Response
類 - 實現類方法:
force_type
- 必須指定app.response_class爲你自定義的Response
- 如果視圖函數返回的數據既不是字符串,也不是元組,也不是Response對象,那麼會將返回值傳給
force_type
,然後將force_type
的返回值返回給前端。#!/usr/bin/python # -*- coding:utf8 -*- from flask import Flask,Response,jsonify import json app = Flask(__name__) app.debug = True #自定義響應 class JSONResponse(Response): @classmethod def force_type(cls, response, environ=None): ''' 這個方法只有視圖函數返回非字符串,非元組,非Response對象纔會調用 :param response: :param environ: :return: ''' print response print type(response) if isinstance(response,dict): #jsonify除了將字典轉換成爲json對象,還將對象封裝成了一個Response對象 response = jsonify(response) #response = json.dumps(response) #這樣轉換的話程序啓動會報錯 return super(JSONResponse,cls).force_type(response,environ) #返回父類信息 app.response_class = JSONResponse @app.route('/') #第一種情況 def hello_world(): #Response('Hello World',status=200,mimetype='text/html') return 'Hello World!' #第二種情況 @app.route('/list1/') def list1(): resp = Response('List1') resp.set_cookie('country','china') return resp #第三種情況 @app.route('/list2') def list2(): return 'list2',200,{'X-Name':'abc'} @app.route('/list3/') def list3(): return {"username":"abc","age":11} if __name__ == '__main__': app.run(host='0.0.0.0')
- 必須繼承自