文章目录

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.1 url和路由的区别。

我们调用接口需要调用的是一段具体的代码,也就是一个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
argsrequest的一个属性,其本质是一个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()

注意:

  1. 1. 自定义动态路由过滤器类,该类必须继承`werkzeug.routing` 的`BaseConverter`类 2. 通过`regex`属性指定路由规则 3. 讲自定义的类映射到`app.url_map.converters`中(其本质是一个字典) `app.url_map.converters['tel'] = TelephoneConverter`

实现效果: ![](https://img-blog.csdnimg.cn/img_convert/b0c003c7a0292324ad15564443bd83f6.png)

3.4.2 自定义动态路由过滤器之处理动态路由

自定义一个类,该通过继承werkzeug.routing 的BaseConverter类不光可以实现正则匹配,我们介绍一下以下两个方法:

  • * 在该类中实现 to_python 方法: 这个方法的返回值,将会传递给视图函数的形参。我们可以利用这个方法实现处理url中动态路由部分。 * 在该类中实现 to_url 方法: 翻转url的时候也就是使用url_for函数的时候,我们传入指定的动态路由部分,触发to_url方法,这个方法的返回值,会拼接在非动态路由上,从而实现生成符合要求的url格式。

![](https://img-blog.csdnimg.cn/img_convert/0aae9de3bf0aa652b925afee187c9c9c.png)

实例:
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()函数传入的动态路由部分由列表转换成拼接字符串了。

2 HTTP请求

1 请求报文和响应报文

打开浏览器,当我们输入一个url,点击访问的时候会向目标服务器发送一个HTTP请求,请求的的时候会发生什么呢,会经过os七层,这里我们不赘述os七层通讯原理,可以理解为通过url我们请求目标服务器的一段具体的资源,可以理解为发送了一个请求,一个请求的本质就是向目标服务器上面发送了一些数据,这种浏览器于服务器之间交互的数据被称为报文。

  • * 请求报文:请求时浏览器发送的数据称为请求报文 * 响应报文:服务器收到了请求返回给浏览器的数据称为响应报文 *提示:这里我们们是BS架构去讲解, BS架构就是浏览器和后端服务器的交互,CS架构是客户端和服务端的交互,BS架构可以理解为CS架构的一个具体实现。浏览器就是客户端,后端服务器就是服务端。*

![](https://img-blog.csdnimg.cn/img_convert/fe1385f246cb9f50fd34391304d87a9f.png)

报文中的GET请求和POST请求

  • * GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. * POST方法是把提交的数据放在HTTP包的请求体中. * GET提交的数据大小有限制(因为浏览器对URL的长度有限制) * POST方法提交的数据没有限制。 * GET与POST请求在服务端获取请求数据方式不同。

**报文实例:** ```python ''' GET请求报文 # 请求首行 GET / HTTP/1.1\r\n # get请求后面的参数 GET /?name=lqz&age=18 HTTP/1.1\r\n # 请求头 Host: 127.0.0.1:8008\r\n Connection: keep-alive\r\n Cache-Control: max-age=0\r\n Upgrade-Insecure-Requests: 1\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\nAccept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9\r\n Cookie: csrftoken=7xx6BxQDJ6KB0PM7qS8uTA892ACtooNbnnF4LDwlYk1Y7S7nTS81FBqwruizHsxF\r\n\r\n' # 请求体(get请求,请求体为空) ''' '''

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
2.3.1 使用request属性获取url

访问: 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测试'
2.3.2 其他request对象常用的属性和方法。

request里面有诸多的方法,先对requests这些方法有个初步印象,随着我们日后的学习会慢慢接触到这些request常用的方法。

3 GET和post的实例:

3.1 常见的HTTP方法见下表:

请求 说明 请求 说明
GET 获取服务器资源 DELETE 删除服务器资源
POST 处理服务器资源 PATCH 在服务器更新资源(客户端提供改变的属性)
PUT 在服务器更新资源(客户端提供改变后的完整资源)

一般常用的请求为GET和POST

3.2 GET请求:

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我们在上一章已经论述过了。
关键词

  • * 使用request.args属性获取get传来的参数,关于args我们在上一章已经论述过了。 * @app.route('/', methods=['GET']) 指定浏览器只能以GET方法访问服务端。

#### 3.3 POST请求: **POST 请求: 会给服务器提交一些数据或者文件,会对服务器的状态产生影响。** 在了解POST请求之前我们先了解一下render_termplate ##### 3.3.1 render_template的简单使用 ```python from flask import Flask, request, render_template ``` 我们暂时只简单的理解render_template模块可以把html文件返回给浏览器并渲染。 如: ![](https://img-blog.csdnimg.cn/img_convert/77dfc7b710f22d6a468170cb20570954.png)

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>

关键词

  • * form标签的`action`指定的是跳转的页面。并且会自动拼接成http://127.0.0.1:5000/login_request/ ​ 也就是本项目的: ip地址+端口+/login_request/ * form标签的`method`指定的是以什么方法请求服务端,此案例中请求的方法为POST方法。

访问127.0.0.1:5000/login/ 后如下图 ![](https://img-blog.csdnimg.cn/img_convert/0387a64e979ce142782afa165b0ae5ab.png)

3.3.2 正式开始我们的POST案例:

项目目录:

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()

关键词

  • * request.form是专门用来针对表单取数据的,在这里如果前端是以表单的形式提交的,我们可以使用request.form来取值 * @app.route() 中的 methods=['POST'] 代表只接收浏览器的POST请求

**templates/login.html** ```python
登录界面 用户: 密码: ``` ![](https://img-blog.csdnimg.cn/img_convert/e2f06fbe479d24228ce20358e2df883d.png)

总体的逻辑是 :

  1. 1. 首先访问127.0.0.1:5000/login/,默认是get请求。 2. 然后`return render_template('login.html')` 返回给浏览器页面。 3. 然后填写内容点击提交,以post方式请求 [http://127.0.0.1:5000/login_request/。](http://127.0.0.1:5000/login_request/%E3%80%82) 4. 然后进入`def login_request()`视图函数 进行逻辑判断返回成功与否。

#### 3.4 一个视图函数同时可以接收GET和POST请求 我们的案例和3.3.2案例完成的业务逻辑是一样的,相当于简化了3.3.2的案例,把两个视图函数合并到一起,利用`request.method`属性可以获取字符串格式的请求方法。来区分本次请求是GET还是POST 实例: **server.py**: ```python from flask import Flask, request, render_template import config

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)

**关键词**:
<ul>
* `@app.route()`的`methods`方法 指定该视图函数接收浏览器传过来的请求方法,可以指定多个。
* `request.method`获取字符串格式的请求方法
</ul>

**templates/login.html**:
```python
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<form action="" method="POST">
用户:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>

其展示效果

3 视图函数和视图类

1 视图函数

之前我们已经了解过了视图函数的大概用法,本节深入了解一下视图函数

1.1 endpoint简介

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.2 装饰器注册路由源码浅析

(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

解析:

  • * ,发现`route()`返回的是`decorator`函数地址,然后基于语法糖和装饰器的原理,decorator会加括号运行,像这样`decorator(source_code_demo)` * `decorator`函数中首先取出`endpoint`,然后运行`self.add_url_rule(rule, endpoint, f, **options)` * **所以** `self.add_url_rule(rule, endpoint, f, **options)`**就是注册路由的核心**

**(3)** 点进`self.add_url_rule(rule, endpoint, f, **options)`查看源码, ​ 再点进`_endpoint_from_view_func(view_func)`查看源码 ```python ...

@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__

解析:

  • * 由上述代码我们可以直到如果没有指定`endpoint`,我们调用了 `_endpoint_from_view_func()` * 观察`_endpoint_from_view_func`函数我们可以知道,返回了视图函数的名字给了`endpoint`赋值 * `methos`没有指定会给methos赋默认值`('GET',)`

**小结:**

  1. 1. `self.add_url_rule(rule, endpoint, f, options)`就是注册路由的核心 2. 观察`_endpoint_from_view_func`函数我们可以知道,返回了视图函数的名字给了`endpoint`赋值 3. `methos`没有指定会给`methods`赋默认值`('GET',)`

![](https://img-blog.csdnimg.cn/img_convert/c4757c6557deef01b794dea25f424cb1.png) ## 1.3 另一种注册路由的方式---app.add_url_rule() 通过看上一个小节写的源码,现在我们知道了app.route() 的核心就是`self.add_url_rule(rule, endpoint, f, options)`就是注册路由的核心。所以我们可以直接使用`app.add_url_rule()`的方式来注册路由。 **实例:** ```python def add_url_test():

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 '个人信息页面'

关键词

  1. 1. 装饰器一定要写在注册路由的下面,写在视图函数的上面。 2. 装饰器内部一定要使用`@wraps(func)`方法,用于保护被装饰函数的属性。

![](https://img-blog.csdnimg.cn/img_convert/96ab9b39c0725b5fdf47635ed1e13cb9.png)

2 视图类

2.1 视图类的基本写法

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')

讲解:

  1. 1. 首先从flask中导入 `views` 2. 写一个类一定要继承 `views.MethodView` 3. 在类中写`methods = ['GET','POST']` 可以指定可接受的请求类型 4. 在类中写`decorators = [login_verify,]`可以指定装饰器,第一个装饰器是最里层函数依次往后包裹 5. 在类中写`def get(self):`用于获取get请求 6. 在类中写` def post(self):`用于获取post请求 7. 添加路由的方法使用 app.add_url_rule( '路由',view_func=CBVTest.as_view(name='自定义一个端点名字'))

其原理是CBVTest.as_view(name='自定义一个端点名字')会返回一个函数,name是为这个函数命的名字,可以通过这个函数进行分发请求等操作。

3 详细讲解注册路由的参数:

常用的参数

@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和端口

Flask框架——详解URL、HTTP请求、视图函数和视图类的更多相关文章

  1. python flask框架详解

    Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档, 英文不好的同学也可以参考中文文档 1.安装flask pi ...

  2. [Cocoa]深入浅出 Cocoa 之 Core Data(1)- 框架详解

    Core data 是 Cocoa 中处理数据,绑定数据的关键特性,其重要性不言而喻,但也比较复杂.Core Data 相关的类比较多,初学者往往不太容易弄懂.计划用三个教程来讲解这一部分: 框架详解 ...

  3. Spark2.1.0——内置Web框架详解

    Spark2.1.0——内置Web框架详解 任何系统都需要提供监控功能,否则在运行期间发生一些异常时,我们将会束手无策.也许有人说,可以增加日志来解决这个问题.日志只能解决你的程序逻辑在运行期的监控, ...

  4. Spark2.1.0——内置RPC框架详解

    Spark2.1.0——内置RPC框架详解 在Spark中很多地方都涉及网络通信,比如Spark各个组件间的消息互通.用户文件与Jar包的上传.节点间的Shuffle过程.Block数据的复制与备份等 ...

  5. 深入浅出 Cocoa 之 Core Data(1)- 框架详解

    深入浅出 Cocoa 之 Core Data(1)- 框架详解 罗朝辉(http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 Core data 是 Cocoa 中处 ...

  6. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  7. php中流行的rpc框架详解

    什么是RPC框架? 如果用一句话概括RPC就是:远程调用框架(Remote Procedure Call) 那什么是远程调用? 我的官方群点击此处. 通常我们调用一个php中的方法,比如这样一个函数方 ...

  8. Shiro 安全框架详解二(概念+权限案例实现)

    Shiro 安全框架详解二 总结内容 一.登录认证 二.Shiro 授权 1. 概念 2. 授权流程图 三.基于 ini 的授权认证案例实现 1. 实现原理图 2. 实现代码 2.1 添加 maven ...

  9. Flask框架cbv的写法、请求与响应、请求扩展、session源码分析、闪现

    本篇文章将会详细讲在flask框架如何写cbv.请求与响应.请求扩展.session源码分析.闪现等知识点. 目录 一.flask写CBV 二.请求与响应 三.session 四.闪现flash 五. ...

  10. jQuery Validate验证框架详解

    转自:http://www.cnblogs.com/linjiqin/p/3431835.html jQuery校验官网地址:http://bassistance.de/jquery-plugins/ ...

随机推荐

  1. SpringBoot集成支付宝 - 少走弯路就看这篇

    最近在做一个网站,后端采用了SpringBoot,需要集成支付宝进行线上支付,在这个过程中研究了大量支付宝的集成资料,也走了一些弯路,现在总结出来,相信你读完也能轻松集成支付宝支付. 在开始集成支付宝 ...

  2. 代码发布平台jenkins中Check-out Strategy选项功能意义

    第一个选项:Use'svn update' as much as possible  这个选项能实现快速发布:Use 'svn update' whenever possible, making th ...

  3. Java protected 关键字详解

    很多介绍Java语言的书籍(包括<Java编程思想>)都对protected介绍的比较的简单,基本都是一句话,就是: 被 protected 修饰的成员对于本包和其子类可见.这种说法有点太 ...

  4. 图像增强—自适应直方图均衡化(AHE)-限制对比度自适应直方图均衡(CLAHE)

    一.自适应直方图均衡化(Adaptive histgram equalization/AHE) 1.简述 自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术.和普通的直方图均衡算 ...

  5. Spring-配置文件(引入其他配置文件,分模块开发)

    引入其他配置文件 实际开发,Spring的配置文件内容非常多,这就导致了Spring配置很复杂且体积很大,所以可以将配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载 & ...

  6. IIC总线学习笔记

    IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板.嵌入式系统或手 ...

  7. JDK源码-StringJoiner源码分析

    背景 功能描述:将多个元素使用指定符号前后连接为字符串:eg:1 2 3 4 5 , => 1,2,3,4,5 要点: 多个元素 指定分隔符 分隔符只在元素之间,不能作为第一或最后一个 使用方法 ...

  8. django.db.utils.OperationalError: (1366, "Incorrect string value: '\\xE5\\xA4\\xAB\\xE4\\xBA\\xBA' f

    1.打开mysql命令行 show variables like '%char%'; 将字符集显示不是utf-8的更改为utf-8 例如:set character_set_database=utf8 ...

  9. G-channel 实现低光图像增强

    G-channel 之前研究低光图像增强时,看到一篇博客,里面介绍了一种方法,没有说明出处,也没有说明方法的名字,这里暂时叫做 G-channel 算法. 博客地址:低照度图像增强(附步骤及源码)_低 ...

  10. React中setState的使用与同步异步

    在react中,修改状态如果直接使用this.state,不会引起组件的重新渲染,需要通过 this.setState来对组件的属性进行修改. 1.this.setState的两种定义方式 定义初始状 ...