Python3 Flask框架(二)——转化器

在开始转换器的内容之前,我们先来看下页面的链接跳转,这在我们的网站中会经常看到:

from flask import Flask
from flask import redirect  # 页面跳转的方法
from flask import url_for   # 通过视图函数名反向推出路由路径

app = Flask(__name__)

app.config.from_pyfile('./config.cfg')

@app.route('/index',methods = ['GET','POST'])
def index():
    return 'This is index page'

@app.route('/login')
def login():
    url = url_for('index')      # 通过视图函数index推出index对应的路由
    return redirect(url)        # 跳转到指定地址

print(app.url_map)

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


我们可以看到,当我们访问/login的时候,马上重定向到了/index,即跳转到了/index下;

 

好了,接下来我们来讲转换器:
设想一种情况,一个购物网站,它有很多类别和商品信息,那么这样就会造成很多的访问链接地址,如果我们一个一个创建肯定不合适,我们可以通过转换器将每种商品的ID提取出来,作为视图函数的参数进行调用,后期再通过数据库将数据进行填充就好了;

from flask import Flask

app = Flask(__name__)

app.config.from_pyfile('./config.cfg')

@app.route('/goods/<int:goods_id>')
# 这里需要说明的是:引号包含的还是路由地址,只是<int:goods_id>就像变量一样,这里int指的就是数据类型,
# 可以为int、float和path三种,默认情况下当做string处理;goods_id就像是变量名一样
# 注意:不可包含/,不然会被误判为地址
def goods_detail(goods_id):    # 这里的参数就是上面通过转换器提取出来的数据
    return 'goods detail page %s' % goods_id

print(app.url_map)

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

通过上面的栗子相信已经基本了解了转换器的作用,那么上面例子的转换规则还是太简单了,还记得正则表达式是怎么使用的嘛,我们可以用正则表达式来定义转换规则:

from werkzeug.routing import BaseConverter
'''
flask中路由部分就是通过werkzeug这个库来实现的,那么我们对路由路径的处理就需要用到这个库
'''

from flask import Flask

app = Flask(__name__)

# 下面我们就需要做一个根据我们自定义正则规则来提取信息的万能转换器
class RegConverter(BaseConverter):      # 定义转换器类,继承父类的属性和方法
    def __init__(self,url_map,regex):   # 初始化操作
    # 我们可以看见有两个参数:regex - 自定义的规则
    # url_map是默认自己添加上去的,在构建默认转换器对象的时候,会把当前整个app应用里的路由列表传到第一个参数里面
        super(RegConverter,self).__init__(url_map)  # 初始化父类
        # 在使用我们自定义的转换器之前,先以父类最原始的方式将对象构建出来,构建出来之后,再把我们定义的参数保存
        self.regex = regex
        # 将正则表达式的规则保存到regex这个属性中,flask会使用这个属性来进行路由的正则匹配

app.url_map.converters['re'] = RegConverter
# 将自定义的转换器添加到flask的应用中

@app.route("/goods/<re('1[234]\d{5}'):goods_id>")
# 上面就是自定义正则规则,[]里面就是限制字符,{n}就是限制字符格式
def goods_detail(goods_id):
    return 'goods_id : %s' % goods_id

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

 

接下来我们来看下转换器的高级应用,从上面我们知道自定义转换器是基于BaseConverter来实现的,那么我们看下这个父类都做了些什么吧:

class BaseConverter(object):
    """Base class for all converters."""

    regex = "[^/]+"    # 我们可以看见默认规则是:在/之前的所有字符
    weight = 100       # 最长为100

    def __init__(self, map):
        self.map = map    # 这就是我们为什么要上传url_map的原因

    def to_python(self, value):
    # 这个方法就是当拿到正则表达式提取后的值,再要如何进行处理,默认是将值直接返回了,我们可以再这个做进一步的出来再返回
        return value

    def to_url(self, value):
    # 这个方法我们从功能代码可以看出来,它对url进行了处理,并且放回了一个合法的url,它在我们进行页面跳转,但是路由路径存在转换器转换的时候存在
        if isinstance(value, (bytes, bytearray)):
            return _fast_url_quote(value)
        return _fast_url_quote(text_type(value).encode(self.map.charset))

我们通过两个例子来分别说明:

  1. to_python()方法的使用:
    from werkzeug.routing import BaseConverter
    
    from flask import Flask
    
    app = Flask(__name__)
    
    class RegConverter(BaseConverter):
        def __init__(self,url_map,regex):
            super(RegConverter,self).__init__(url_map)
            self.regex = regex
        def to_python(self, value):
            return 'py'+value    # 对返回结果进行处理
    
    app.url_map.converters['re'] = RegConverter
    
    @app.route("/goods/<re('1[234]\d{5}'):goods_id>")
    def goods_detail(goods_id):
        return 'goods_id : %s' % goods_id
    
    if __name__ == '__main__':
        app.run(debug=True)

    我们发现,跟之前的代码,所有的定义规则什么都是一样的,但是在输出的时候却多了‘py’,这是因为在获得转换结果之后,在对结果返回之前,我们在代码中进行了处理,所以返回的值不是转换之后得到的值了;我们可以在这一步对数据进行加密,或者其他操作;
  2. to_url()的意义是什么呢?
    我们在文章最开始的时候说了,网页和网页之间会存在跳转关系,并且可以通过url_for(视图函数)推出路由的地址,那么现在问题来了,当我的路由是有转换器转换的,地址就是不确定的,需要根据我们的参数来进行跳转,那么to_url()就是用来根据我们传入的参数来返回当前的路由地址的;我们来举个栗子看下:
    from werkzeug.routing import BaseConverter
    from flask import Flask
    from flask import url_for
    from flask import redirect
    
    app = Flask(__name__)
    
    class RegConverter(BaseConverter):
        def __init__(self,url_map,regex):
            super(RegConverter,self).__init__(url_map)
            self.regex = regex
    
    app.url_map.converters['re'] = RegConverter
    
    @app.route("/goods/<re('1[234]\d{5}'):goods_id>")
    def goods_detail(goods_id):
        return 'goods_id : %s' % goods_id
    
    @app.route('/index')
    def index():
        url = url_for('goods_detail',goods_id='1234567')
        # 这里需要注意的是:要和视图函数的参数对应,以键值对的方式进行赋值
        return redirect(url)
    
    if __name__ == '__main__':
        app.run(debug=True)



    我们可以看见当访问 /index 的时候,页面马上发声了跳转,证明我们的实验室成功的;
    当然我们也可以对to_url()的处理方法进行修改;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章