我在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路由中的转换器,但我不确定它是如何工作的,因为我使用的是烧瓶蓝图。
提前致谢!
答案 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)的编码,[
和]
与相比看起来很丑陋。
让转换器进入特定的蓝图(以及单元测试)是你的练习。