Flask重定向url_for更改参数类型

时间:2015-08-04 02:58:38

标签: python flask url-routing

我在Flask / python中有以下代码,它涉及一个变量年份,即一个int列表。但是,当我使用return redirect(url_for(...时,年份变为unicode,如果已经[2015,2014],则变为'[','2','0','1','5','',等...

@main.route('/search', methods=('GET','POST'))
def fysearch():
    form = SelectYear()
    if form.validate_on_submit():
        years = form.years.data
        return redirect(url_for('.yearresults', years=years))
    return render_template('select_year.html', form=form)

当我打印上面几年中每个元素的类型时,它是我想要的普通int。一旦它被传递到重定向url_for,那就是几年变成unicode。

@main.route('/searchresults/<years>')
def yearresults(years):
    page = request.args.get('page', 1, type=int)
    print type(years)
    pagination = Grant.query.filter(Grant.fy.in_(years)).\
            paginate(page, per_page=current_app.config['POSTS_PER_PAGE'],
        error_out=False)
    return render_template('yearresults.html', years=years, entries=pagination.items, pagination=pagination

我知道有几种方法可以在将数据传递给yearresults(years)之后将其恢复为一个列表,例如年= json.loads(年)或替换[和]并分裂,但我想知道如果有不同的方法来解决这个问题。我已经考虑过url路由中的转换器,但我不确定它是如何工作的,因为我使用的是烧瓶蓝图。 提前致谢!

1 个答案:

答案 0 :(得分:1)

函数url_for返回一个URL,它实际上是一个字符串 - 你不能将一个int列表混合成一个实际上是字符串的值(在更好的语言/框架中你会得到一个类型错误,更多以这种方式工作,但不像你正在经历的那样容易出现概念错误。您只需返回url_for('.yearresults', years=years)的结果即可查看,并看到该值看起来像/yearresults/%5B2014%2C%202015%5D。很明显,year的值是一个字符串,因为它是默认的转换器(因为你没有定义一个)。因此,懒惰的方法是使用JSON或某种字符串格式对years进行编码并在yearresults处理程序上对其进行解码,但是您有正确的想法使用来自converter的{{3}} werkzeug包。

无论如何,将它们放在一起你可以做到这样的事情:

from werkzeug.routing import BaseConverter
from werkzeug.routing import ValidationError

class ListOfIntConverter(BaseConverter):
    def __init__(self, url_map):
        super(ListOfIntConverter, self).__init__(url_map)

    def validate(self, value):
        if not isinstance(value, list):
            return False

        for i in value:
            if not isinstance(i, int):
                return False

        return True

    def to_python(self, value):
        try:
            return [int(i) for i in value.split(',')]
        except (TypeError, ValueError) as e:
            raise ValidationError()

    def to_url(self, value):
        if not self.validate(value):
            # Or your specific exception because this should be from the
            # program.
            raise ValueError
        return ','.join(unicode(v) for v in value)

app.url_map.converters['listofint'] = ListOfIntConverter

@app.route('/years/<listofint:years>')
def years(years):
    return '%d, %s' % (len(years), years)

这有利于在此路由的输入不匹配时直接生成404(即为<years>提供字符串的人),并避免%编码形式的{{1}来自基于JSON(或基于repr)的编码,[]相比看起来很丑陋。

让转换器进入特定的蓝图(以及单元测试)是你的练习。

相关问题