Flask框架——详解URL、HTTP请求、视图函数和视图类

文章目录

    • 1 什么是url?
    • 3 如何应用url?
      • 3.1url和路由的区别。
      • 3.2 url传参的两种
        • 3.2.1动态路由传参
          • 3.2.1.1 动态路由的过滤
        • 3.3.4 url_for如何处理动态的视图函数?
        • 3.3.5 url_for如何为url添加查询字符串?
      • 3.4 自定义动态路由过滤器
        • 3.4.1 自定义动态路由过滤器之正则匹配
        • 3.4.2 自定义动态路由过滤器之处理动态路由
          • 实例:
  • 2 HTTP请求
      • 1 请求报文和响应报文
          • 2.3.1 使用request属性获取url
          • 2.3.2 其他request对象常用的属性和方法。
      • 3 GET和post的实例:
        • 3.1 常见的HTTP方法见下表:
        • 3.2 GET请求:
          • 3.3.2 正式开始我们的POST案例:
  • 3 视图函数和视图类
    • 1 视图函数
      • 1.1 endpoint简介
      • 1.2 装饰器注册路由源码浅析
    • 2 视图类
      • 2.1 视图类的基本写法
    • 3 详细讲解注册路由的参数:
      • 常用的参数
      • 不常用的参数(了解)

1 什么是url?

url是统一资源定位符(Uniform Resource Locator的简写),对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
Flask框架——详解URL、HTTP请求、视图函数和视图类_第1张图片

一个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](https://www.oldboyedu.com/Public/linux/?fr=aladdin#23) ,#后面的23就是锚点
## 2 为什么要有url? 顾名思义统一资源定位符,是用来做定位用的,我们的web开发无非是要调用程序,而调用的具体程序我们称之为python的视图函数,URL建立了与Python视图函数一一对应的映射关系,通俗易懂可以理解为一条命令触发了一个python的函数或类。 ![](https://img-blog.csdnimg.cn/img_convert/aaa9bbd79cab3e3da858cea170549088.png)

3 如何应用url?

3.1url和路由的区别。

我们调用接口需要调用的是一段具体的代码,也就是一个python类或者python函数,而url就是对这段代码的具体映射,也就是说我们可以通过url找到一个具体的python类或者python函数,这便是url。而路由是根据url定位到具体的pyhon类或python函数的程序,这段程序我们称之为路由。
Flask框架——详解URL、HTTP请求、视图函数和视图类_第2张图片

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

Flask框架——详解URL、HTTP请求、视图函数和视图类_第3张图片

3.2 url传参的两种

Flask框架——详解URL、HTTP请求、视图函数和视图类_第4张图片

3.2.1动态路由传参

如果你仔细观察日常所用服务的某些URL格式,会发现很多地址中都包含可变部分。例如,你想根据学生的id找到具体的学生,http://127.0.0.1:5000/student_list// 仍然在path部分 ,但是你没必要写多个路由,我们Flask支持这种可变的路由。
见代码:

@app.route('/student_list//')
def student_list(student_id):
    return '学生{}号的信息'.format(student_id)

Flask框架——详解URL、HTTP请求、视图函数和视图类_第5张图片

关键字:在path中有可变的部分 ,达到了传参的效果,我们称之为动态路由传参

3.2.1.1 动态路由的过滤

可以对参数限定数据类型,比如上面的文章详情,限定student_id必须为整数类型

@app.route('/student_list//')
def article_detail(student_id):
    return '学生{}号的信息'.format(student_id)

Flask框架——详解URL、HTTP请求、视图函数和视图类_第6张图片

Flask框架——详解URL、HTTP请求、视图函数和视图类_第7张图片

主要有这几种类型过滤:
  string: 默认的数据类型,接收没有任何斜杠"\ /"的字符串
  int: 整型
  float: 浮点型
  path: 和string类型相似,但是接受斜杠,如:可以接受参数/aa/bb/cc/多条放在一起
  uuid: 只接受uuid格式的字符串字符串,
✔提示:uuid为全宇宙唯一的串
Flask框架——详解URL、HTTP请求、视图函数和视图类_第8张图片

上面几种约束均为如下格式,例子中的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)

Flask框架——详解URL、HTTP请求、视图函数和视图类_第9张图片

Flask框架——详解URL、HTTP请求、视图函数和视图类_第10张图片
动态路由的适用场景?
如果想增加网站的曝光率,可以考虑使用动态路由,因为是把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`属性。 例: ```python 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)
   ![](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的执行。如图
Flask框架——详解URL、HTTP请求、视图函数和视图类_第11张图片

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//')
def student(id):
    return 'student {}'.format(id)

控制台输出:
Flask框架——详解URL、HTTP请求、视图函数和视图类_第12张图片

浏览器输出:
Flask框架——详解URL、HTTP请求、视图函数和视图类_第13张图片

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'

控制台输出:
Flask框架——详解URL、HTTP请求、视图函数和视图类_第14张图片

浏览器输出:
Flask框架——详解URL、HTTP请求、视图函数和视图类_第15张图片

3.4 自定义动态路由过滤器

Flask框架——详解URL、HTTP请求、视图函数和视图类_第16张图片

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

Flask框架——详解URL、HTTP请求、视图函数和视图类_第17张图片

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//')
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()方法把访问时候动态路由部分被处理成列表了。
Flask框架——详解URL、HTTP请求、视图函数和视图类_第18张图片

证明我们的 to_url() 方法把url_for()函数传入的动态路由部分由列表转换成拼接字符串了。
Flask框架——详解URL、HTTP请求、视图函数和视图类_第19张图片

2 HTTP请求

1 请求报文和响应报文

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

  • * 请求报文:请求时浏览器发送的数据称为请求报文 * 响应报文:服务器收到了请求返回给浏览器的数据称为响应报文 *✔提示:这里我们们是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对象常用的属性和方法。

Flask框架——详解URL、HTTP请求、视图函数和视图类_第21张图片

request里面有诸多的方法,先对requests这些方法有个初步印象,随着我们日后的学习会慢慢接触到这些request常用的方法。
Flask框架——详解URL、HTTP请求、视图函数和视图类_第22张图片

3 GET和post的实例:

3.1 常见的HTTP方法见下表:

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

一般常用的请求为GET和POST

3.2 GET请求:

Flask框架——详解URL、HTTP请求、视图函数和视图类_第23张图片

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案例:

项目目录:
Flask框架——详解URL、HTTP请求、视图函数和视图类_第24张图片

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)

Flask框架——详解URL、HTTP请求、视图函数和视图类_第25张图片

Flask框架——详解URL、HTTP请求、视图函数和视图类_第26张图片

总体的逻辑是 :

  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)

**关键词**:  
    * `@app.route()`的`methods`方法 指定该视图函数接收浏览器传过来的请求方法,可以指定多个。 * `request.method`获取字符串格式的请求方法
​ **templates/login.html**: ```python 登录界面
用户: 密码:

其展示效果

Flask框架——详解URL、HTTP请求、视图函数和视图类_第27张图片

Flask框架——详解URL、HTTP请求、视图函数和视图类_第28张图片

3 视图函数和视图类

1 视图函数

之前我们已经了解过了视图函数的大概用法,本节深入了解一下视图函数
Flask框架——详解URL、HTTP请求、视图函数和视图类_第29张图片

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)

Flask框架——详解URL、HTTP请求、视图函数和视图类_第30张图片

关键词:
利用@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请求、视图函数和视图类_第31张图片

Flask框架——详解URL、HTTP请求、视图函数和视图类_第32张图片

你可能感兴趣的:(Flask框架,flask,http,python)