简体   繁体   English

烧瓶重定向url_用于更改参数类型

[英]Flask redirect url_for changing type of parameter

I have the following code in Flask/python that involves a variable years that is a list of ints. 我在Flask / python中有以下代码,涉及可变年份,该年份是一个整数列表。 However, when I use return redirect(url_for(... , years becomes unicode and if it had been [2015, 2014], it becomes '[','2','0','1','5',' ', etc... 但是,当我使用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)

When I print the type of each element in years above, it is a normal int as I want it to be. 当我在上面的年份中打印每个元素的类型时,这是我想要的一个正常的int值。 Once it is passed into the redirect url_for, that is when years turns into unicode. 一旦将其传递到重定向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

I know there are ways to revert years back to a list of ints after it has been passed to yearresults(years) like years=json.loads(years) or replacing the [ and ] and splitting, but I was wondering if there is a different way to fix this issue. 我知道有一些方法可以在将年传递回yearresults(years)还原为整数列表,例如years = json.loads(years)或替换[和]并进行拆分,但是我想知道是否存在一个解决此问题的其他方法。 I have thought about a converter in the url routing, but I am not sure how that works since I am using flask blueprints. 我曾在URL路由中考虑过转换器,但由于使用瓶状蓝图,因此我不确定该转换器如何工作。 Thanks in advance! 提前致谢!

The function url_for returns a URL, which is effectively a string - you can't mix a list of ints into a value that's effectively a string (in better languages/frameworks you will get a type error, more work that way but less prone to conceptual errors like what you are experiencing). 函数url_for返回一个URL,该URL实际上是一个字符串-您不能将一个整数列表混入一个实际上是字符串的值中(在更好的语言/框架中,您会遇到类型错误,这样做会更多,但更不容易概念错误(例如您遇到的错误)。 You can check simply by returning the result of url_for('.yearresults', years=years) and see that the value looks something like /yearresults/%5B2014%2C%202015%5D . 您可以简单地通过返回url_for('.yearresults', years=years)的结果进行检查url_for('.yearresults', years=years)然后看到该值看起来像/yearresults/%5B2014%2C%202015%5D Clearly that value in place for year is a string as that is the default converter (since you did not define one). 显然, year值是一个字符串,因为它是默认转换器(因为您没有定义一个)。 So the lazy way out is to encode years with JSON or some sort of string format and decode that on the yearresults handler, however you had the right idea with using a converter which is from the werkzeug package. 因此,懒惰的解决方法是使用JSON或某种字符串格式对years进行编码,并在yearresults处理程序上对其进行解码,但是使用来自werkzeug包的转换器是正确的主意。

Anyway, putting that together you could do something like this: 无论如何,将它们放在一起,您可以执行以下操作:

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)

This has the advantage of generating a 404 directly when the input to this route do not match (ie someone supplying a string for <years> ), and avoids the % encoded form of [ , ] , and 这具有产生一个404直接在输入到该路由不匹配(即,某人供给的字符串的优点<years> ),并避免了%的编码形式[] ,和 from a JSON (or the repr) based encoding ( %5B2014%2C%202015%5D looks way ugly when compared to 2014,2015 ). 来自基于JSON(或repr)的编码(与2014,2015相比, %5B2014%2C%202015%5D看起来很难看)。

Getting the converter into a specific blueprint (and also the unit tests for that) is your exercise. 您需要练习将转换器转换为特定的蓝图(并为此进行单元测试)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM