02-01 詳解url
1 什么是url?
url是統一資源定位符(Uniform Resource Locator的簡寫),對可以從互聯網上得到的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標准資源的地址。互聯網上的每個文件都有一個唯一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎么處理它。
一個URL由以下幾部分組成:
scheme://host:port/path/?parameter=xxx#anchor
https://www.baidu.com/Public/linux/?fr=aladdin#23
- scheme:代表的是訪問的協議,一般為http或者https以及ftp等。
- host:主機名,域名,比如www.baidu.com。
- port:端口號。當你訪問一個網站的時候,瀏覽器默認使用80端口。
- path:路徑。比如:www.baidu.com/Public/linux/?python=aladdin#23,www.baidu.com后面的Public/linux就是path。
- query-string:查詢字符串,比如:www.baidu.com/s?wd=python,?后面的python=aladdin就是查詢字符串。
- anchor:錨點,后台一般不用管,前端用來做頁面定位的。比如:https://www.oldboyedu.com/Public/linux/?fr=aladdin#23 ,#后面的23就是錨點
2 為什么要有url?
顧名思義統一資源定位符,是用來做定位用的,我們的web開發無非是要調用程序,而調用的具體程序我們稱之為python的視圖函數,URL建立了與Python視圖函數一一對應的映射關系,通俗易懂可以理解為一條命令觸發了一個python的函數或類。
3 如何應用url?
3.1url和路由的區別。
我們調用接口需要調用的是一段具體的代碼,也就是一個python類或者python函數,而url就是對這段代碼的具體映射,也就是說我們可以通過url找到一個具體的python類或者python函數,這便是url。而路由是根據url定位到具體的pyhon類或python函數的程序,這段程序我們稱之為路由。
在Flask程序中使用路由我們稱之為注冊路由,是使用程序實例提供的app.route()裝飾器注冊路由,而括號內的字符串就是url,注冊路由的過程就是完成了 url和python類或函數映射的過程,可以理解為會有一張表保存了url與python類或函數的對應關系。這樣我們以url訪問flask就可以找到對應的程序。
例:
@app.route('/')
def hello_world():
return 'Hello World!'
按照這種關系我們再寫一個路由
@app.route('/student_list/')
def student_list():
return 'students'
3.2 url傳參的兩種
3.2.1動態路由傳參
如果你仔細觀察日常所用服務的某些URL格式,會發現很多地址中都包含可變部分。例如,你想根據學生的id找到具體的學生,http://127.0.0.1:5000/student_list/<student_id>/ 仍然在path部分 ,但是你沒必要寫多個路由,我們Flask支持這種可變的路由。
見代碼:
@app.route('/student_list/<student_id>/')
def student_list(student_id):
return '學生{}號的信息'.format(student_id)
關鍵字:在path中有可變的部分 ,達到了傳參的效果,我們稱之為動態路由傳參
3.2.1.1 動態路由的過濾
可以對參數限定數據類型,比如上面的文章詳情,限定student_id必須為整數類型
@app.route('/student_list/<int:student_id>/')
def article_detail(student_id):
return '學生{}號的信息'.format(student_id)
主要有這幾種類型過濾:
string
: 默認的數據類型,接收沒有任何斜杠"\ /"的字符串
int
: 整型
float
: 浮點型
path
: 和string類型相似,但是接受斜杠,如:可以接受參數/aa/bb/cc/多條放在一起
uuid
: 只接受uuid格式的字符串字符串,
✔提示:uuid為全宇宙唯一的串
上面幾種約束均為如下格式,例子中的int可以換為 string,float,path,uuid
:
@app.route('/student_list/<int:student_id>/')
def article_detail(student_id):
return '學生{}號的信息'.format(student_id)
any
: 可以指定多種路徑,如下面的例子
url_path的變量名是自己定義的
@app.route('/<any(student,class):url_path>/<id>/')
def item(url_path, id):
if url_path == 'student':
return '學生{}詳情'.format(id)
else:
return '班級{}詳情'.format(id)
動態路由的適用場景?
如果想增加網站的曝光率,可以考慮使用動態路由,因為是把path作為參數,搜索引擎的算法會定義你為一個靜態頁面,不會經常改變,有利於搜索引擎的優化。但是如果是公司內部的管理系統就沒有必要使用動態路由,因為內部系統對曝光率沒有要求。
關鍵詞:
- 上面我們接受參數使用的是path(路徑)形式,這種傳參的形式就叫動態路由傳參,有利於搜索引擎的優化。
3.2.2 查詢字符串傳參
我們上面介紹了什么是查詢字符串:
如果我們在瀏覽器中輸入www.baidu.com/s?wd=python&ad=flask的參數,這個 ?
后的key=value便是查詢字符串,
可以寫多個key=value用&
相連我們將查詢字符串作為參數去請求我們的flask程序,這便是查詢字符串傳參。
我們之前再注冊路由的時候會在里面的path
部分以及函數的形參
設置參數來接受path的參數,我們在查詢字符串傳參的時候需要從flask
模塊里面導入request
對象,用request.args
屬性在我們的程序中根據查詢字符串的key
取出查詢字符串的value
。
args
是request
的一個屬性,其本質是一個Werkzeug
依賴包的的immutableMultiDict
的對象,用於解析我們傳入的查詢字符串,immutableMultiDict
對象也繼承了Dict
類,所以可以使用字典的.get()
方法來獲取,當然了如果我們有獲取原生未解析的原生查詢字符串的需求,可以使用query_string
屬性。
例:
from flask import Flask,request
...
@app.route('/student_name/')
def school_name_list():
name = request.args.get('name')
age = request.args.get('age')
return "學生的姓名為{},年齡為{}".format(name, age)
3.3 url_for()的使用:
3.3.1簡介視圖函數:
我們在訪問一個網址的時候在調用flask項目的時候需要調用的是一段具體的代碼,也就是一個python類或者python函數,在這里這個python類我們稱之為視圖類,python函數我們稱之為視圖函數。
3.3.2 url_for()的作用:
如果我們在視圖函數中想使用一個url,比如給前端返回,或者我們在這個視圖函數中返回一個模板文件都會使用到url,url相當於一把鑰匙可以開啟一些資源。如果你修改了注冊路由編寫的url規則,相當於修改了鑰匙。那么其他的視圖函數依舊是使用了原來的鑰匙就無效了,如果項目是一個大項目,你一點點手動的去改涉及到的的url就不合理了。url_for()就是用來解決這個問題的。
3.3.3url_for()的原理:
利用視圖函數名字一般不會改變的特性,利用視圖函數的名字
去動態精准的獲取url,以便於開發使用。
url_for('視圖函數名字') # 輸出該視圖函數url
具體例子:
from flask import Flask,url_for
app = Flask(__name__)
app.config.update(DEBUG=True)
@app.route('/')
def demo1():
print(url_for("book")) # 注意這個引用的是視圖函數的名字 字符串格式
print(type(url_for("book")))
return url_for("book")
@app.route('/book_list/')
def book():
return 'flask_book'
if __name__ == "__main__":
app.run()
我們直接訪問http://127.0.0.1:5000/,經過路由的分發會觸發demo1的執行。如圖
3.3.4 url_for如何處理動態的視圖函數?
如果想獲取動態路由,必須以關鍵字實參的形式為動態的path部分賦值,注意動態的path部分必須被賦值,
案例:
@app.route('/demo2/')
def demo2():
student_url = url_for('student', id=5, name='mark') # id 就是動態path的key 必須賦值, # name 將作為查詢字符串傳入
print(student_url)
return student_url
@app.route('/student/<int:id>/')
def student(id):
return 'student {}'.format(id)
控制台輸出:
瀏覽器輸出:
3.3.5 url_for如何為url添加查詢字符串?
如果想在路徑后面拼出來查詢字符串,以關鍵字實參的形式放到url_for()里面作為參數,會自動拼成路徑
案例:
@app.route('/demo3/')
def demo3():
school_url = url_for('school', school_level='high', name='college')
# 具體要拼接的查詢參數 以關鍵字實參的形式寫在url_for里
print(school_url)
return school_url
@app.route('/school/')
def school():
return 'school message'
控制台輸出:
瀏覽器輸出:
3.4 自定義動態路由過濾器
3.4.1 自定義動態路由過濾器之正則匹配
我們可以通過繼承werkzeug.routing 的BaseConverter
類從而自己定義一個動態路由過濾器的規則
from flask import Flask,request
from werkzeug.routing import BaseConverter
app = Flask(__name__)
app.debug =True
class TelephoneConverter(BaseConverter):
regex = '1[3857]\d{9}' #右下斜杠d
app.url_map.converters['tel'] = TelephoneConverter
@app.route('/student/<tel:telenum>/')
def student_detail(telenum):
return '學生的手機號碼是{}'.format(telenum)
if __name__ == '__main__':
app.run()
注意:
-
自定義動態路由過濾器類,該類必須繼承
werkzeug.routing
的BaseConverter
類 -
通過
regex
屬性指定路由規則 -
講自定義的類映射到
app.url_map.converters
中(其本質是一個字典)app.url_map.converters['tel'] = TelephoneConverter
實現效果:
3.4.2 自定義動態路由過濾器之處理動態路由
自定義一個類,該通過繼承werkzeug.routing 的BaseConverter
類不光可以實現正則匹配,我們介紹一下以下兩個方法:
-
在該類中實現 to_python 方法:
這個方法的返回值,將會傳遞給視圖函數的形參。我們可以利用這個方法實現處理url中動態路由部分。
-
在該類中實現 to_url 方法:
翻轉url的時候也就是使用url_for函數的時候,我們傳入指定的動態路由部分,觸發to_url方法,這個方法的返回值,會拼接在非動態路由上,從而實現生成符合要求的url格式。
實例:
from flask import Flask,request,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
app.debug =True
class ListConverter(BaseConverter):
regex = '.*' # 這個regex代表都匹配的意思,可以根據自己的需求制定url規則
def to_python(self, value):
'''這個函數用於拿到了路由里的動態參數賦值給value,
可以在to_python進行操作動態參數,
返回操作完的的結果給視圖函數的形參'''
return value.split('+')
def to_url(self, value):
'''這個函數用於和url_for連用,
url_for通過指定給動態參數(以關鍵字實參的形式)賦值給value
我們可以根據我們的需求操作url_for傳進來的參數,
然后返回一個理想的動態路由內容拼接在url上'''
return '+'.join(value)
app.url_map.converters['list'] = ListConverter
@app.route('/student_list/<list:students>/')
def student_list(students):
print(url_for('student_list',students=['a','b'])) # 輸出 /student_list/a+b/
return '{}'.format(students)
if __name__ == '__main__':
app.run()
證明to_python()
方法把訪問時候動態路由部分被處理成列表了。
證明我們的 to_url()
方法把url_for()
函數傳入的動態路由部分由列表轉換成拼接字符串了。