url是统一资源定位符(Uniform Resource Locator的简写),对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
一个URL由以下几部分组成:
scheme://host:port/path/?parameter=xxx#anchor
https://www.baidu.com/Public/linux/?fr=aladdin#23
我们调用接口需要调用的是一段具体的代码,也就是一个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'
如果你仔细观察日常所用服务的某些URL格式,会发现很多地址中都包含可变部分。例如,你想根据学生的id找到具体的学生,http://127.0.0.1:5000/student_list/
见代码:
@app.route('/student_list//' )
def student_list(student_id):
return '学生{}号的信息'.format(student_id)
关键字:在path中有可变的部分 ,达到了传参的效果,我们称之为动态路由传参
可以对参数限定数据类型,比如上面的文章详情,限定student_id必须为整数类型
@app.route('/student_list//' )
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//' )
def article_detail(student_id):
return '学生{}号的信息'.format(student_id)
any
: 可以指定多种路径,如下面的例子
url_path的变量名是自己定义的
@app.route('///' )
def item(url_path, id):
if url_path == 'student':
return '学生{}详情'.format(id)
else:
return '班级{}详情'.format(id)
动态路由的适用场景?
如果想增加网站的曝光率,可以考虑使用动态路由,因为是把path作为参数,搜索引擎的算法会定义你为一个静态页面,不会经常改变,有利于搜索引擎的优化。但是如果是公司内部的管理系统就没有必要使用动态路由,因为内部系统对曝光率没有要求。
关键词:
return "学生的姓名为{},年龄为{}".format(name, age)
![](https://img2018.cnblogs.com/blog/1825659/201910/1825659-20191009221154012-1905288238.png)
![](https://img2018.cnblogs.com/blog/1825659/201910/1825659-20191009221132366-279922593.png)
### 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,以便于开发使用。
```python
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的执行。如图
如果想获取动态路由,必须以关键字实参的形式为动态的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//' )
def student(id):
return 'student {}'.format(id)
如果想在路径后面拼出来查询字符串,以关键字实参的形式放到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'
我们可以通过继承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//' )
def student_detail(telenum):
return '学生的手机号码是{}'.format(telenum)
if __name__ == '__main__':
app.run()
注意:
自定义一个类,该通过继承werkzeug.routing 的BaseConverter
类不光可以实现正则匹配,我们介绍一下以下两个方法:
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//' )
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()
函数传入的动态路由部分由列表转换成拼接字符串了。
打开浏览器,当我们输入一个url,点击访问的时候会向目标服务器发送一个HTTP请求,请求的的时候会发生什么呢,会经过os七层,这里我们不赘述os七层通讯原理,可以理解为通过url我们请求目标服务器的一段具体的资源,可以理解为发送了一个请求,一个请求的本质就是向目标服务器上面发送了一些数据,这种浏览器于服务器之间交互的数据被称为报文。
报文中的GET请求和POST请求
POST请求报文
# 请求首行
POST /?name=lqz&age=18 HTTP/1.1\r\n
# 请求头
Host: 127.0.0.1:8008\r\nConnection: keep-alive\r\n
Content-Length: 21\r\nCache-Control: max-age=0\r\n
Origin: http://127.0.0.1:8008\r\nUpgrade-Insecure-Requests: 1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36\r\n Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nReferer: http://127.0.0.1:8008/?name=lqz&age=18\r\n
Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=7xx6BxQDJ6KB0PM7qS8uTA892ACtooNbnnF4LDwlYk1Y7S7nTS81FBqwruizHsxF\r\n\r\n
# 请求体
name=lqz&password=123'
'''
![](https://img2018.cnblogs.com/blog/1825659/201910/1825659-20191009222153150-801230202.png)
### 2 request对象
#### 2.1什么是request对象?
request对象封装解析了请求报文中的数据,其大部分功能是由依赖包werkzeug完成的,并且每个request对象都是线程隔离的,保证了数据的安全性。
#### 2.2为什么要有request对象?
request对象解决了很多问题,各种请求的方法以及请求参数的格式都不一致,所以flask帮我们做了一个request对象,专门去解析各种方法以及各种格式的请求,以便于去开发使用。
#### 2.3 requst对象的常用方法
request对象使用需要从flask模块中导入
```python
from flask import Flask, request
访问: http://127.0.0.1:5000/student_list/?name=mark :
表2-1 使用request的属性获取url
属性 | 解析值 | 属性 | 解析值 |
---|---|---|---|
path | u‘/student_list/’ | base_url | u’http://127.0.0.1:5000/student_list/’ |
full_path | u‘/student_list/?name=mark’ | url | u’http://127.0.0.1:5000/student_list/?name=mark’ |
host | u’127.0.0.1:5000’ | url_root | u’http://127.0.0.1:5000/’ |
host_url | u’http://127.0.0.1:5000/’ |
request的解析结果如下。
@app.route('/student_list/')
def student_list():
print(request.path) # 输出 /student_list/
print(request.full_path) # 输出 /student_list/?name=mark
print(request.host) # 输出 127.0.0.1:5000
print(request.host_url) # 输出 http://127.0.0.1:5000/
print(request.base_url) # 输出 http://127.0.0.1:5000/student_list/
print(request.url) # 输出 http://127.0.0.1:5000/student_list/?name=mark
print(request.url_root) # 输出 http://127.0.0.1:5000/
return 'request.urldemo测试'
request里面有诸多的方法,先对requests这些方法有个初步印象,随着我们日后的学习会慢慢接触到这些request常用的方法。
请求 | 说明 | 请求 | 说明 |
---|---|---|---|
GET | 获取服务器资源 | DELETE | 删除服务器资源 |
POST | 处理服务器资源 | PATCH | 在服务器更新资源(客户端提供改变的属性) |
PUT | 在服务器更新资源(客户端提供改变后的完整资源) |
一般常用的请求为GET和POST
GET请求一般用于在服务器上获取资源,不会更改服务器的状态。
GET实例:
@app.route('/', methods=['GET']) # 不写methods也可以 默认就接收get请求
def demo_get():
print(request.args.get('name')) # 输出 mark
return '{}请求'.format(request.method)
结合request对象,使用request.args属性获取get传来的参数,关于args我们在上一章已经论述过了。
关键词:
server.py
from flask import Flask, request, render_template
...
@app.route('/login/',methods=['GET'])
def login():
return render_template('login.html')
...
注意:render_template()会去flask根目录下的templates里面寻找文件,所以给的参数路径是相对路径。
关键词:render_template()中放的文件路径是与templates文件夹相对的路径
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<form action="/login_request/" method="POST">
用户:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
关键词
server.py
from flask import Flask, request, render_template
import config
app = Flask(__name__)
@app.route('/login_request/',methods=['POST'])
def login_request():
print(request.form.get('username')) # 'mark'
print(request.form.get('password')) # '123'
if request.form.get('username') == 'mark' and request.form.get('password') == '123':
return 'success'
else:
return 'error'
@app.route('/login/',methods=['GET'])
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run()
关键词:
总体的逻辑是 :
app = Flask(name)
@app.route(‘/login_inner/’,methods=[‘POST’,‘GET’])
def login_inner():
if request.method == ‘GET’: #判断本次请求是否为get请求
return render_template(‘login.html’)
if request.form.get(‘username’) == ‘mark’ and request.form.get(‘password’) == ‘123’:
return ‘success’
return ‘error’
if name == ‘main’:
app.run(debug=True)
**关键词**:
* `@app.route()`的`methods`方法 指定该视图函数接收浏览器传过来的请求方法,可以指定多个。
* `request.method`获取字符串格式的请求方法
**templates/login.html**:
```python
登录界面
之前我们已经了解过了视图函数的大概用法,本节深入了解一下视图函数
endpint
参数是写在注册路由的装饰器中的一个参数,学名叫端点,我们可以理解为函数的别名。原来我们翻转视图函数的url
的时候是直接通过是如函数的名字,如url_for('函数名')
,现在我们可以指定一个endpoint='fbv'
参数来进行翻转url
。如果不指定endpoint,默认就以函数名作为端点名。
实例:
@app.route('/fbvtest/',methods=['GET','POST'],endpoint='fbv')
def fbvtest():
url_demo = url_for('fbv')
return '利用视图函数别名翻转的url为:{}'.format(url_demo)
关键词:
利用@app.route()
的endpoint='fbv'
参数可以自由指定端点名,url_for可以根据指定的端点名进行翻转。
(1) 首先写一个小视图函数
#注册装饰器的原理
#1 v = app.route('/source_code_demo/',endpoint='source_code')
#2 v(source_code_demo)
@app.route('/source_code_demo/',endpoint='source_code')
def source_code_demo():
return 'source_code_demo'
(2) 查看app.route()
源码
...
def route(self, rule, **options):
...
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
解析:
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None,
provide_automatic_options=None, **options):
…
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint
methods = options.pop('methods', None)
# if the methods are not given and the view_func object knows its
# methods we can use that instead. If neither exists, we go with
# a tuple of only ``GET`` as default.
if methods is None:
methods = getattr(view_func, 'methods', None) or ('GET',)
...
```python
def _endpoint_from_view_func(view_func):
"""Internal helper that returns the default endpoint for a given
function. This always is the function name.
"""
assert view_func is not None, 'expected view func if endpoint ' \
'is not provided.'
return view_func.__name__
解析:
return '实现了add_url方式注册路由'
# url 端点 函数地址
app.add_url_rule(‘/add_url_test/’,endpoint=‘add_demo’,view_func=add_url_test)
![](https://img2018.cnblogs.com/blog/1825659/201910/1825659-20191009223409813-960893827.png)
## 1.4 视图函数中添加自定义装饰器
我们在平时的开发的过程中,很多需要权限验证的功能需要用到装饰器,下面的代码是如何在flask中实现一个装饰器。
```python
from flask import Flask, request
from functools import wraps
app = Flask(__name__)
def login_verify(func):
@wraps(func)
def wrapper(*args, **kwargs):
user_name = request.args.get('user')
password = request.args.get('password')
if user_name == 'mark' and password == '123':
return func(*args,**kwargs)
else:
return '请登录'
return wrapper
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/my_info/')
@login_verify
def my_info():
return '个人信息页面'
关键词:
from flask import Flask, views, request, url_for
from functools import wraps
def login_verify(func):
@wraps(func)
def wrapper(*args, **kwargs):
user_name = request.args.get('user')
password = request.args.get('password')
if user_name == 'mark' and password == '123':
return func(*args,**kwargs)
else:
return '请登录'
return wrapper
class CBVTest(views.MethodView):
methods = ['GET','POST'] # 指定可以接收的方法有什么
decorators = [login_verify,] # 指定自定义的装饰器
def get(self):
print(url_for('cbvtest'))
return 'cbv_get'
def post(self):
return 'cbv_post'
app.add_url_rule('/cbvtest',view_func=CBVTest.as_view(name='cbvtest'),endpoint='end_demo')
讲解:
其原理是CBVTest.as_view(name='自定义一个端点名字')
会返回一个函数,name是为这个函数命的名字,可以通过这个函数进行分发请求等操作。
@app.route和app.add_url_rule参数:
rule, URL规则
view_func, 视图函数名称
endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
methods = None, 允许的请求方式,如:["GET", "POST"]
(1) 对URL最后的 / 符号是否严格要求 strict_slashes = False
strict_slashes = False
'''
@app.route('/index', strict_slashes=False)
#访问http://www.xx.com/index/ 或http://www.xx.com/index均可
@app.route('/index', strict_slashes=True)
#仅访问http://www.xx.com/index
'''
(2) 重定向到指定地址redirect_to=“ ”
@app.route("/",redirect_to='/home/')
def index():
return '根路径'
@app.route("/home/")
def admin_demo():
return 'home路径'
(3) 为函数提供默认参数值
defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
**(4)**子域名设置subdomain=“ ”
from flask import Flask,url_for
app = Flask(__name__)
app.debug = True
'''
先在hosts设置域名解析(就是在本机的hosts文件上编辑上域名对应ip的关系)
域名解析会先解析本地如果没有再解析dns服务器
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 mark.com
127.0.0.1 admin.mark.com
'''
app.config['SERVER_NAME'] = 'mark.com:5000' # 这个代表访问这个域名的时候要访问5000端口
@app.route("/")
def index():
return '设置域名成功'
@app.route("/admin_demo/",subdomain='admin')
def admin_demo():
return '设置子域名成功'
'''
在浏览器中访问主域名
mark.com:5000/
在浏览器中访问子域名
admin.mark.com:5000/admin_demo/
注意:后面跟的path路径部分正常写
'''
if __name__ == '__main__':
app.run(host='127.0.0.1',port=5000) # 测试服务器不稳定,尽量手动制定ip和端口