首页 > 其他分享 >【3.0】flask之路由系统

【3.0】flask之路由系统

时间:2023-08-26 21:45:21浏览次数:40  
标签:__ index None endpoint flask app 3.0 route 路由

【一】路由系统基于装饰器

from flask import Flask

app = Flask(__name__)


# (1) flask 的路由系统基于装饰器
# rule : 路径
# methods : 请求方式【列表】
# endpoint :别名

# @app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')
@app.route('/index', methods=['GET'])
def index():
    return 'hello world'


if __name__ == '__main__':
    app.run()

【二】转换器

  • 默认转化器
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}
from flask import Flask

app = Flask(__name__)

# (2) 默认转换器
'''
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}
'''


# 常用 string  path  int
# @app.route('/index/<string:name>', methods=['GET'])

@app.route('/index', methods=['GET'])
def index(name):
    
    return 'hello world'


if __name__ == '__main__':
    app.run()

【三】路由系统的本质

【1】执行流程分析

from flask import Flask

app = Flask(__name__)

# (3)路由系统的本质
# @app.route('/index', methods=['GET']) 本质上是一个装饰器
# 执行时  ---> index = @app.route('/index', methods=['GET'])(index)
@app.route('/index', methods=['GET'])
def index():
    return 'hello world'


if __name__ == '__main__':
    app.run()
  • 执行@app.route('/index', methods=['GET'])
  • 本质上执行了index = @app.route('/index', methods=['GET'])(index)
  • 触发了 route 方法中的 decorator
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
    def decorator(f: T_route) -> T_route:
        endpoint = options.pop("endpoint", None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f # f 是视图函数 ,在这里并没有对视图函数进行额外的处理,只是加了一些参数
    return decorator
  • 所以本质上执行了index = decorator(index)

【2】分析 decorator 函数

def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
    def decorator(f: T_route) -> T_route:
        endpoint = options.pop("endpoint", None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator
  • f 是视图函数 ,在这里并没有对视图函数进行额外的处理,只是加了一些参数
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
  • 视图函数执行 @app.route('/index', methods=['GET'])

    • endpoint 携带在 route 内
    • 从 options 中弹出 endpoint ,有则弹出,无则 None
  • 核心 self.add_url_rule(rule, endpoint, f, **options)

    • self 就是 app 对象
    • app.add_url_rule('路由地址', '路由的别名', '视图函数', '其他参数')
from flask import Flask

app = Flask(__name__)

# @app.route('/index', methods=['GET'])
def index():
    return 'hello world'

# 自定义注册路由和视图
app.add_url_rule('/index', 'index', index, '其他参数')

if __name__ == '__main__':
    app.run()

【3】add_url_rule 的参数详解

# URL规则
rule

# 视图函数名称
view_func

# 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}为函数提供参数
defaults = None

# 名称,用于反向生成URL,即: url_for('名称')
endpoint = None

# 允许的请求方式,如:["GET", "POST"]
methods = None,

#对URL最后的 / 符号是否严格要求
strict_slashes = None
    '''
        @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
    '''
#重定向到指定地址
redirect_to = None, 
    '''
        @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
    '''

#子域名访问
subdomain = None, 
    '''
    #C:\Windows\System32\drivers\etc\hosts
    127.0.0.1       www.liuqingzheng.com
	127.0.0.1       admin.liuqingzheng.com
	127.0.0.1       buy.liuqingzheng.com
    
    from flask import Flask, views, url_for
    app = Flask(import_name=__name__)
    app.config['SERVER_NAME'] = 'liuqingzheng.com:5000'
    @app.route("/", subdomain="admin")
    def static_index():
        """Flask supports static subdomains
        This is available at static.your-domain.tld"""
        return "static.your-domain.tld"
    #可以传入任意的字符串,如传入的字符串为aa,显示为 aa.liuqingzheng.com
    @app.route("/dynamic", subdomain="<username>")
    def username_index(username):
        """Dynamic subdomains are also supported
        Try going to user1.your-domain.tld/dynamic"""
        return username + ".your-domain.tld"
    if __name__ == '__main__':
        app.run()
        
    访问:
    http://www.liuqingzheng.com:5000/dynamic
    http://admin.liuqingzheng.com:5000/dynamic
    http://buy.liuqingzheng.com:5000/dynamic
    '''

【4】 endpoint 详解

(1)自解版

  • 当我们在视图函数中不传 endpoint 时,会走以下流程
from flask import Flask

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()
  • 触发 decorator 方法
def decorator(f: T_route) -> T_route:
    endpoint = options.pop("endpoint", None)
    self.add_url_rule(rule, endpoint, f, **options)
    return f
  • 此时 endpoint 是None
  • 接着会触发 Falsk 父类中的 add_url_rule 方法
def add_url_rule(
        self,
        rule: str,
        endpoint: str | None = None,
        view_func: ft.RouteCallable | None = None,
        provide_automatic_options: bool | None = None,
        **options: t.Any,
) -> None:
    if endpoint is None:
        endpoint = _endpoint_from_view_func(view_func)  # type: ignore
    options["endpoint"] = endpoint
    methods = options.pop("methods", None)
  • 此时会走到 endpoint = _endpoint_from_view_func(view_func) 方法
def _endpoint_from_view_func(view_func: t.Callable) -> str:
    """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__
  • 此时的 view_func 就是我们的视图函数

    • 返回 视图函数的吗,名字作为 endpoint
  • 由此也就解释了为什么在使用装饰器时,需要指定 endpoint 参数

    • 如果指定 endpoint 参数,就会按照我们指定的参数进行逻辑判断

      • 如果不指定 endpoint 参数,每次视图函数都会将 装饰器的 inner 传入

      • 所有的 endpoint 参数都是一样的,从而引发了 ennpoint 错误

          def add_url_rule(
              self,
              rule: str,
              endpoint: str | None = None,
              view_func: ft.RouteCallable | None = None,
              provide_automatic_options: bool | None = None,
              **options: t.Any,
          ) -> None:
              raise NotImplementedError
      
    • 也可以是用 wrapper 包装我们的装饰器

      • 包装后的装饰器就是我们的函数本身,而不再是inner函数

(2)参考版

在Flask中,当我们在视图函数中不传递endpoint参数时,会按照一定的流程生成默认的endpoint。下面我们来详细解释这个过程。

  1. 首先,我们定义一个Flask应用和一个路由装饰器@app.route('/'),该装饰器将视图函数index()与根路由'/'进行关联。
from flask import Flask

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()
  1. 当使用装饰器时,会触发装饰器方法decorator,其中会获取options中的endpoint参数(如果存在),如果不存在则为None
def decorator(f: T_route) -> T_route:
    endpoint = options.pop("endpoint", None)
    self.add_url_rule(rule, endpoint, f, **options)
    return f
  1. 接着,会调用Flask父类中的add_url_rule方法,该方法用于将路由规则和视图函数进行关联。在这个过程中,会检查传入的endpoint参数是否为None,如果是None,则会通过视图函数名称来生成默认的endpoint
def add_url_rule(
        self,
        rule: str,
        endpoint: str | None = None,
        view_func: ft.RouteCallable | None = None,
        provide_automatic_options: bool | None = None,
        **options: t.Any,
) -> None:
    if endpoint is None:
        endpoint = _endpoint_from_view_func(view_func)  # type: ignore
    options["endpoint"] = endpoint
    methods = options.pop("methods", None)
  1. _endpoint_from_view_func方法中,它会根据视图函数来生成默认的endpoint。如果视图函数为空,则会抛出异常;否则,会返回视图函数的名称作为默认的endpoint
def _endpoint_from_view_func(view_func: t.Callable) -> str:
    assert view_func is not None, "expected view func if endpoint is not provided."
    return view_func.__name__
  1. 这就解释了为什么在使用装饰器时,有时需要通过指定endpoint参数来避免endpoint错误的发生。如果不指定endpoint参数,每次视图函数都会将装饰器内部函数传入add_url_rule方法作为view_func参数,并生成相同的endpoint。这样就会导致所有路由都具有相同的endpoint,进而引发endpoint冲突异常。

为了避免这种情况,我们可以使用wrapper函数包装装饰器。这样包装后的装饰器本身就是我们定义的函数,并且不再是内部函数。通过这种方式,每个路由装饰器都会拥有自己独立的endpoint,并且不会产生冲突。

from flask import Flask

app = Flask(__name__)

def my_decorator(f):
    @app.route('/', methods=['GET'], endpoint='my_endpoint')
    def wrapper():
        return f()
    return wrapper

@my_decorator
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()
  • 通过以上的解释和扩充,我们更加详细地了解了在Flask中生成默认endpoint的过程,并介绍了避免endpoint冲突的方法。

标签:__,index,None,endpoint,flask,app,3.0,route,路由
From: https://www.cnblogs.com/dream-ze/p/17659500.html

相关文章

  • 【2.0】flask框架之配置文件
    【一】引入django有settings配置文件所有web框架都会有配置文件-配置文件的形式可能不太一样【二】flask的配置文件【1】配置方式一(简单配置)importuuidfromflaskimportFlaskapp=Flask(__name__)#配置方式一:只能配置debug和secret_keyapp.debug=True......
  • 【4.0】Flask框架之CBV
    【一】基本使用fromflaskimportFlask,render_template#template_folder默认就是当前文件夹下的templates可以不写app=Flask(__name__,template_folder='templates')#FBV:基于函数的视图@app.route('/index',methods=['GET'])defindex():return......
  • 2023.08.24T3 - brain - solution
    brainProblem给定一棵以\(1\)为根的树,给定树上所有点权与边权。记\(d(i,j)\)表示\(i\)到\(j\)的路径长度。定义一棵树的权值为:\[\sum\limits_{i=1}^{n-1}\sum\limits_{j=i+1}^{n}a_{i}a_{j}d(i,j)\]定义一次对点\(i\)的改造操作为:删掉\(i\)与其父节......
  • 网络之路由器交换机的设置
    一、基础知识之(交换机的)虚接口vlan1.端口加入vlan[S1]interfaceGigabitEthernet0/0/1[S1-GigabitEthernet0/0/1]portlink-typeaccess接口模式配置为access模式[S1-GigabitEthernet0/0/1]portdefaultvlan2接口加入vlan2<S1>displayvlan 查看当前配置的vlan ......
  • HCL AppScan Standard v10.3.0 (Windows) - 应用程序安全测试
    HCLAppScanStandardv10.3.0(Windows)-应用程序安全测试请访问原文链接:https://sysin.org/blog/appscan-10/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgESG技术评论:使用HCLAppScan实现持续的应用程序安全“AppScan通过直接集成到软件开发生命周期来支......
  • EHole(棱洞)3.0 红队重点攻击系统指纹探测工具
    https://github.com/lemonlove7/EHole_magic 在进行web打点时,信息收集中对目标进行指纹识别是必不可少的一个环节,使用EHole识别出来的重点资产还要用其他漏洞利用工具去检测,非常的不方便,在原本的基础上加了个漏洞检测功能。提打点的效率。(不影响原版功能的使用)运行流程对资产......
  • 路由反射器
    在使用BGP路由协议的网络中,为保证IBGP对等体之间的连通性,需要在IBGP对等体之间建立全连接关系。假设在一个AS内部有n台路由器,那么应该建立的IBGP连接数就为n(n-1)/2.当IBGP对等体数目很多时,对网络资源和CPU资源的消耗都很大。路由反射器的定义利用路由反射可以解决这一问题。在......
  • BGP联盟和路由反射器
    在谈BGP联盟和BGP反射器这两个技术前,我们先来了解一下BGP中存在的路由黑洞问题。什么是路由黑洞呢?我们以下面这个拓扑来详细的介绍一下:这是一个典型的BGP应用组网。图中,有3个AS,AS之间运行BGP协议。AS65008域内运行OSPF协议。R1和R5上只运行BGP协议,R2和R4上运行OSPF和BGP协议,R3......
  • wpf路由事件简述
    比如在一个窗体中放一个容器,容器中再放一个按钮,添加按钮的鼠标点击事件,再添加容器的鼠标点击事件,然后添加窗体的鼠标点击事件,那么当我们触发按钮的鼠标点击事件后如果不设置e.handle=true就会继续执行容器的鼠标点击事件然后再执行窗体的鼠标点击事件,这就是路由事件的概念。......
  • 路由的过滤器设置
             ......