簡體   English   中英

Flask-Restful端點拋出werkzeug.routing.BuildError

[英]Flask-Restful Endpoint Throwing werkzeug.routing.BuildError

我正在使用Flask-Restful和SQLAlchemy開發API,並且遇到了我有解決方法的行為,但是我不確定堅持該解決方法是否是一個好的長期策略。

相當標准的API,具有帶有POST功能的列表項資源和帶有GET功能的項單一資源。 我通過curl和Web表單測試了POST函數,並收到以下錯誤消息:

BuildError: Could not build url for endpoint 'brand' with values ['_sa_instance_state']. Did you forget to specify values ['brand_symbol']?

奇怪的是,添加一條打印語句(請參見下面的資源聲明末尾附近的注釋注釋)可以使錯誤消失。

而且我知道,即使遇到錯誤消息

  • 該項目已成功提交到數據庫中,並且
  • 在項目上執行GET可以完美顯示URI

因此,基於此,我認為問題可能出在POST return語句上。 我們將不勝感激地獲得任何幫助-我不想忍受不穩定的解決方法!

終點

api.add_resource(BrandListResource, '/brands', endpoint = 'brands')
api.add_resource(BrandResource, '/brands/<string:brand_symbol>', endpoint = 'brand')

資源資源

brand_fields = {
    'id': fields.Integer,
    'brand_symbol': fields.String,
    'brand_name': fields.String,
    'uri': fields.Url('brand', absolute=True)
}

class BrandResource(Resource):
    @marshal_with(brand_fields)
    def get(self, brand_symbol):
        brand = db.session.query(Brand).filter(Brand.brand_symbol == brand_symbol).first()
        if not brand:
            abort(404, message="Brand {} doesn't exist".format(brand_symbol))
        return brand

class BrandListResource(Resource):
    @marshal_with(brand_fields)
    def get(self):
        brands = db.session.query(Brand).all()
        return brands

    @marshal_with(brand_fields)
    def post(self):
        parsed_args = parser.parse_args()
        brand_symbol = parsed_args['brand_symbol']
        brand_name = parsed_args['brand_name']

        brand = db.session.query(Brand).filter(Brand.brand_symbol == brand_symbol).first()
        if brand:
            abort(404, message="Brand {} already exists".format(brand_symbol))

        brand = Brand(brand_symbol=brand_symbol, brand_name=brand_name)
        db.session.add(brand)
        db.session.commit()

        #print brand
        return brand, 201

SQLAlchemy模型

class Brand(db.Model):
    __tablename__ = 'brand'

    id = db.Column(db.Integer, primary_key=True)
    brand_symbol = db.Column(db.String(5), unique=True)
    brand_name = db.Column(db.String(200), nullable=False)

    def __init__(self, brand_symbol, brand_name):
        self.brand_symbol = brand_symbol
        self.brand_name = brand_name

    def __repr__(self):
        return '<brand_symbol {}>'.format(self.brand_symbol)

完整錯誤回溯

Traceback (most recent call last):
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 477, in wrapper
    resp = resource(*args, **kwargs)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 587, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 682, in wrapper
    return marshal(data, self.fields, self.envelope), code, headers
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 640, in marshal
    return OrderedDict([(envelope, OrderedDict(items))]) if envelope else OrderedDict(items)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 57, in __init__
    self.__update(*args, **kwds)
  File "/Users/skavie/testproject/lib/python2.7/_abcoll.py", line 571, in update
    for key, value in other:
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/__init__.py", line 639, in <genexpr>
    for k, v in fields.items())
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask_restful/fields.py", line 307, in output
    o = urlparse(url_for(endpoint, _external=self.absolute, **data))
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/helpers.py", line 332, in url_for
    return appctx.app.handle_url_build_error(error, endpoint, values)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/app.py", line 1811, in handle_url_build_error
    reraise(exc_type, exc_value, tb)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/flask/helpers.py", line 322, in url_for
    force_external=external)
  File "/Users/skavie/testproject/lib/python2.7/site-packages/werkzeug/routing.py", line 1758, in build
    raise BuildError(endpoint, values, method, self)
BuildError: Could not build url for endpoint 'brand' with values ['_sa_instance_state']. Did you forget to specify values ['brand_symbol']?

提交SQLAlchemy會話時, brand對象已過期。 stacktrace通過指出由於您要返回的對象中缺少某些信息而無法構建url來提供提示。

在這種情況下, brand對象需要刷新,因此它將再次包含所有數據。 您可以通過打印它來做到這一點,但是像這樣使用會話的refresh()方法似乎要好一些:

...
db.session.commit()
db.session.refresh(brand)
return brand, 201

需要注意的是,在編寫本文時,refresh方法的文檔指出以下內容:

請注意,高度隔離的事務將返回與先前在同一事務中讀取的值相同的值,而不管該事務之外的數據庫狀態如何變化-使用refresh()通常僅在非ORM SQL語句在數據庫中發出時才有意義。正在進行的事務,或者如果打開了自動提交模式。

這意味着您要重新獲取的信息可能已過時,但是我想在這種情況下這幾乎是理論上的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM