使用Flask-Restful的两个变量URL

0 投票
3 回答
2427 浏览
提问于 2025-04-17 23:43
'/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 字段,要么使用路由中已有的字段。

撰写回答