使用Flask-Restful的两个变量URL
'/api/v1.0/restaurant/<name>'
这看起来是一个常见的问题,但我找不到相关的文档。
我正在写一个API,想让网址看起来像这样:
'/api/v1.0/restaurant/Name&Address'
我使用Flask-restful定义了这个网址:
'/api/v1.0/restaurant/<name>&<address>'
但是,Werkzeug不喜欢这样,结果在werkzeug/routing.py里出现了BuildError的错误。
当我用add_resource定义网址,并且直接写死地址时,一切都正常。
我该如何定义网址,以便能接收两个变量呢?
编辑
Traceback (most recent call last):
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 397, in wrapper
resp = resource(*args, **kwargs)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 487, in dispatch_request
resp = meth(*args, **kwargs)
File "/home/ubuntu/Hotsauce/api/app/views.py", line 75, in get
resto = {'restaurant': marshal(restaurant, resto_fields)}
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 533, in marshal
return OrderedDict(items)
File "/usr/lib/python2.7/collections.py", line 52, in __init__
self.__update(*args, **kwds)
File "/home/ubuntu/.virtualenvs/data/lib/python2.7/_abcoll.py", line 547, in update
for key, value in other:
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask_restful/__init__.py", line 532, in <genexpr>
for k, v in fields.items())
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask_restful/fields.py", line 232, in output
o = urlparse(url_for(self.endpoint, _external = self.absolute, **data))
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/helpers.py", line 312, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/app.py", line 1641, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/flask/helpers.py", line 305, in url_for
force_external=external)
File "/home/ubuntu/.virtualenvs/data/local/lib/python2.7/site-packages/werkzeug/routing.py", line 1620, in build
raise BuildError(endpoint, values, method)
BuildError: ('restaurant', {u'city_id': 2468, u’score’: Decimal('0E-10'), 'id': 37247, u'nbhd_id': 6596, u'address_region': u'NY', u'phone_number': u'(718) 858-6700', '_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x26f33d0>, u'complete': False, u'name': u'Asya', u'address_locality': u'New York', u'address_updated': True, u'street_address': u'46 Henry St'}, None)
以下是生成错误的相关代码:
resto_fields = {
'id': fields.Integer,
'name': fields.String,
'street_address': fields.String,
'address_locality': fields.String,
'address_region': fields.String,
‘score’: fields.Float,
'phone_number': fields.String,
'uri': fields.Url('restaurant')
}
def get(self, name, address):
restaurant = session.query(Restaurant).filter_by(name=name).filter_by(address=address)
resto = {'restaurant': marshal(restaurant, resto_fields)}
return resto
3 个回答
0
我花了一些时间才搞明白这个,所以我来给出一个更正的答案...
@Martijn的回答在这个情况下不太正确。
正确的说法是:你需要在你的数据字典中包含get
方法所需的属性(而不是在输出字段中)。
所以你的代码应该这样写:
resto_fields = {
'id': fields.Integer,
'name': fields.String,
'street_address': fields.String,
'address_locality': fields.String,
'address_region': fields.String,
‘score’: fields.Float,
'phone_number': fields.String,
'uri': fields.Url('restaurant')
}
def get(self, name, address):
restaurant = session.query(Restaurant).filter_by(name=name).filter_by(address=address)
# restaurant must have an 'address' field
restaurant['address'] = ' '.join[restaurant['street_address'], restaurant['address_locality']]
resto = {'restaurant': marshal(restaurant, resto_fields)}
return resto
address
将不会出现在生成的响应中。
1
这不是最理想的解决办法,但至少能让事情运转起来。
问题出现在 flask-restful 尝试在处理数据时创建资源的链接(uri)时。
当链接只需要名字作为变量时,这个问题并不存在。但是,一旦链接需要名字和地址两个变量,就会出现一个叫做 BuildError 的错误。
为了绕过这个问题,我从
'uri': fields.Url('restaurant')
中去掉了这个部分,然后在处理完资源后自己构建了链接,并在返回之前把它加到处理好的资源里。
resto = {'restaurant': marshal(restaurant, resto_fields)}
resto['restaurant']['uri'] = '/api/v1.0/restaurant/{0}&{1}'.format(name, address)
return resto
如果有人有更好的解决办法,我非常想听听。
2
这和 &
符号或者使用多个网址参数没有关系。
你只能在你的接口中使用 resto_fields
输出字段的映射;在你的 resto_fields
映射中没有 address
这个字段,但你的 restaurant
接口需要这个字段来构建网址。
要么在你的输出字段中添加一个 address
字段,要么使用路由中已有的字段。