使用Flask-Restful的两个可变URL

时间:2014-03-24 20:31:41

标签: python flask url-routing flask-restful

这似乎会出现很多问题,但我找不到任何文档。

我正在写一个api,我希望网址看起来像这样:

'/api/v1.0/restaurant/Name&Address'

使用Flask-restful,我已将网址定义为

'/api/v1.0/restaurant/<name>&<address>'

然而Werkzeug并不喜欢这样,并在werkzeug / routing.py中引发了一个BuildError

当我使用add_resource定义url时,为

'/api/v1.0/restaurant/<name>'

并硬连接地址,一切正常。

如何定义带两个变量的网址?

修改

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 :(得分:2)

这与&&符号无关,也与使用多个URL参数无关。

您只能使用端点中resto_fields输出字段映射中的条目;你的address映射中没有 resto_fields条目,但你的restaurant端点要求它构建网址。

在输出字段中添加address字段,使用路线中的一个现有字段。

答案 1 :(得分:1)

这不太理想,但它让事情有效。

在使用resto_fields进行编组期间,当burn-restful试图为资源创建uri时,问题就出现了。

当url仅将name作为变量时,这不是问题,但是,一旦url需要名称和地址,就会引发BuildError。

为解决此问题,我删除了

'uri': fields.Url('restaurant')
来自restos_fields的

,在编组资源后构造了uri,并在返回之前将其添加到编组资源中。

    resto = {'restaurant': marshal(restaurant, resto_fields)}

    resto['restaurant']['uri'] = '/api/v1.0/restaurant/{0}&{1}'.format(name, address)
    return resto

如果有人有更优雅的方式来完成这项工作,我很想听到它。

答案 2 :(得分:0)

我花了一段时间来弄清楚这一点,所以纠正的答案......

对于这种情况,@ Martijn的回答并不完全正确。

正确的是:您必须拥有数据字典中<{1}}方法所需的属性(输出字段中的)。

所以你的代码应该像这样工作:

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 成为生成的响应的一部分