【已解决】Flask-Restful的api出错:AttributeError dict object has no attribute _sa_instance_state

Flask-Restful的api,运行出错:

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:63]:
self=<runningfast.resources.Task.TaskAPI object at 0x7f0f2f175450>

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:101]:
self.rootArgs={‘itemTypeStr’: u’Small’, ‘errandorBill’: {u’errandFee’: 20.0}, ‘unparsed_arguments’: {}, ‘initiatorEndLocation’: {u’latitude’: 120.733463, u’longitude’: 31.278478, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u6c38\u73ca\u8def\u4e2d\u56fd\u4eba\u6c11\u5927\u5b66\u82cf\u5dde\u6821\u533a’}, ‘initiatorDescription’: u’initiator Description’, ‘initiatorStartLocation’: {u’latitude’: 120.719816, u’longitude’: 31.292745, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u897f\u534e\u6797\u8857\u53cc\u6e56\u6e7e\u82b1\u56edIII\u671f’}}

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:123]:
self.rootArgs={‘itemTypeStr’: u’Small’, ‘errandorBill’: {u’errandFee’: 20.0}, ‘unparsed_arguments’: {}, ‘initiatorEndLocation’: {u’latitude’: 120.733463, u’longitude’: 31.278478, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u6c38\u73ca\u8def\u4e2d\u56fd\u4eba\u6c11\u5927\u5b66\u82cf\u5dde\u6821\u533a’}, ‘initiatorDescription’: u’initiator Description’, ‘initiatorStartLocation’: {u’latitude’: 120.719816, u’longitude’: 31.292745, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u897f\u534e\u6797\u8857\u53cc\u6e56\u6e7e\u82b1\u56edIII\u671f’}}

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:126]:
initiatorStartLocation={u’latitude’: 120.719816, u’longitude’: 31.292745, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u897f\u534e\u6797\u8857\u53cc\u6e56\u6e7e\u82b1\u56edIII\u671f’}

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:128]:
initiatorEndLocation={u’latitude’: 120.733463, u’longitude’: 31.278478, u’shortStr’: u’\u6c5f\u82cf\u7701\u82cf\u5dde\u5e02\u5434\u4e2d\u533a\u6c38\u73ca\u8def\u4e2d\u56fd\u4eba\u6c11\u5927\u5b66\u82cf\u5dde\u6821\u533a’}

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:130]:
initiatorDescription=initiator Description

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:132]:
itemTypeStr=Small

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:134]:
errandorBill={u’errandFee’: 20.0}

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:137]:
type(initiatorStartLocation)=<type ‘dict’>, type(initiatorEndLocation)=<type ‘dict’>, type(itemTypeStr)=<type ‘unicode’>, type(errandorBill)=<type ‘dict’>

<div–<——————————————————————————

<div–<——————————————————————————

DEBUG in Task [/root/RunningFast/staging/runningfast/resources/Task.py:140]:
itemType=ItemType.Small

<div–<——————————————————————————

[2016-10-20 20:22:38 +0000] [24693] [ERROR] Error handling request /runningfast/api/v1.0/users/user-bb22f24e-3c27-4e7b-867a-b855e139b295/tasks
Traceback (most recent call last):
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 135, in handle
    self.handle_request(listener, req, client, addr)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 176, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
    return self.wsgi_app(environ, start_response)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 271, in error_router
    return original_handler(e)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 268, in error_router
    return self.handle_error(e)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 477, in wrapper
    resp = resource(*args, **kwargs)
  File "/root/RunningFast/staging/runningfast/resources/Accesstoken.py", line 134, in decorated_function
    return f(*args, **kwargs)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_restful/__init__.py", line 587, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/root/RunningFast/staging/runningfast/resources/Task.py", line 146, in post
    db.session.add(newTask)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 157, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1677, in add
    self._save_or_update_state(state)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1695, in _save_or_update_state
    halt_on=self._contains_state):
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2681, in cascade_iterator
    visited_states, halt_on))
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1552, in cascade_iterator
    get_all_pending(state, dict_)
  File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 770, in get_all_pending
    ret = [(instance_state(current), current)]
AttributeError: ‘dict’ object has no attribute ‘_sa_instance_state’

对应代码:

class TaskAPI(Resource):
    decorators = [login_required]
    def __init__(self):
        gLog.debug("self=%s", self)
        self.rootParser = reqparse.RequestParser()
        self.rootParser.add_argument(‘initiatorStartLocation’,
                                   type=dict,
                                   location=’json’)
        self.rootParser.add_argument(‘initiatorEndLocation’,
                                   type=dict,
                                   location=’json’),
        self.rootParser.add_argument(‘initiatorDescription’,
                                   type=unicode,
                                   default="",
                                   location=’json’)
        self.rootParser.add_argument(‘itemTypeStr’,
                                   type=unicode,
                                   default="",
                                   location=’json’)
        self.rootParser.add_argument(‘errandorBill’,
                                   type=dict,
                                   location=’json’),
        self.rootArgs = self.rootParser.parse_args()
        self.initiatorStartLocationParser = reqparse.RequestParser()
        self.initiatorStartLocationParser.add_argument(‘longitude’, type=float,  location=(‘initiatorStartLocation’,))
        self.initiatorStartLocationParser.add_argument(‘latitude’, type=float,   location=(‘initiatorStartLocation’,))
        self.initiatorStartLocationParser.add_argument(‘shortStr’, type=unicode, location=(‘initiatorStartLocation’,))
        self.initiatorStartLocationArgs = self.initiatorStartLocationParser.parse_args(req=self.rootArgs)
        self.initiatorEndLocationParser = reqparse.RequestParser()
        self.initiatorEndLocationParser.add_argument(‘longitude’, type=float,  location=(‘initiatorEndLocation’,))
        self.initiatorEndLocationParser.add_argument(‘latitude’, type=float,   location=(‘initiatorEndLocation’,))
        self.initiatorEndLocationParser.add_argument(‘shortStr’, type=unicode, location=(‘initiatorEndLocation’,))
        self.initiatorEndLocationArgs = self.initiatorEndLocationParser.parse_args(req=self.rootArgs)
        self.errandBillParser = reqparse.RequestParser()
        self.errandBillParser.add_argument(‘errandFee’, type=float, location=(‘errandorBill’,))
        self.errandBillArgs = self.errandBillParser.parse_args(req=self.rootArgs)
        gLog.debug("self.rootArgs=%s", self.rootArgs)
        super(TaskAPI, self).__init__()
    def get(self, userId, taskId):
        gLog.debug("self.rootArgs=%s", self.rootArgs)
        if userId == "":
            return genRespFailDict(code=90101, message="user id can not empty")
        if taskId == "":
            return genRespFailDict(code=90102, message="task id can not empty")
        curTask = Task.query.filter_by(id=taskId).first()
        gLog.debug(‘curTask=%s’, curTask)
        if curTask is None:
            return genRespFailDict(code=90102, message="not found user for id %s"%(userId))
        return genRespSuccessfulDict(message="found user", dataJson=marshal(curTask, task_fields))
    def post(self, userId):
        gLog.debug("self.rootArgs=%s", self.rootArgs)
        initiatorStartLocation = self.rootArgs["initiatorStartLocation"]
        gLog.debug("initiatorStartLocation=%s", initiatorStartLocation)
        initiatorEndLocation = self.rootArgs["initiatorEndLocation"]
        gLog.debug("initiatorEndLocation=%s", initiatorEndLocation)
        initiatorDescription = self.rootArgs["initiatorDescription"]
        gLog.debug("initiatorDescription=%s", initiatorDescription)
        itemTypeStr = self.rootArgs["itemTypeStr"]
        gLog.debug("itemTypeStr=%s", itemTypeStr)
        errandorBill = self.rootArgs["errandorBill"]
        gLog.debug("errandorBill=%s", errandorBill)
        gLog.debug("type(initiatorStartLocation)=%s, type(initiatorEndLocation)=%s, type(itemTypeStr)=%s, type(errandorBill)=%s",
                   type(initiatorStartLocation), type(initiatorEndLocation), type(itemTypeStr), type(errandorBill))
        itemType = ItemType(itemTypeStr)
        gLog.debug("itemType=%s", itemType)
        newTask = Task(
            itemType = itemType,
            initiatorId = userId,
            initiatorStartLocation = initiatorStartLocation)
        db.session.add(newTask)
        gLog.debug(‘before flush newTask=%s’, newTask)
        db.session.flush()
        gLog.debug("after  flush newTask=%s", newTask)
        db.session.commit()
        gLog.debug(‘added newTask=%s’, newTask)
        return genRespSuccessfulDict(message="create new task ok", dataJson=marshal(newTask, task_fields))

此处,看起来很明显:

实际上是:

flask-restful中的RequestParser已经可以正常解析,嵌套的json参数了。

但是对于装饰器login_required,无法支持dict类型变量,导致出错。

AttributeError dict  _sa_instance_state

python – SQLalchemy AttributeError: ‘str’ object has no attribute ‘_sa_instance_state’ – Stack Overflow

python – Flask-Restless & Marshmallow: ‘dict’ object has no attribute ‘_sa_instance_state’ – Stack Overflow

看错了。

实际上是:

db.session.add(newTask)

出错的

-》看来是此处把dict的变量initiatorStartLocation,传递到,要求是Location对象的变量中了

所以导致出错。

所以去用initiatorStartLocation中的值,去初始化对应的Location,然后再传入,估计就可以了。

即:

        newInitiatorStartLocation = Location(longitude=initiatorStartLocation["longitude"],
                                             latitude=initiatorStartLocation["latitude"],
                                             shortStr=initiatorStartLocation["shortStr"],
                                             fullStr=initiatorStartLocation["fullStr"])

或:

        newInitiatorStartLocation = Location()
        newInitiatorStartLocation.longitude = initiatorStartLocation["longitude"]
        newInitiatorStartLocation.latitude = initiatorStartLocation["latitude"]
        newInitiatorStartLocation.shortStr = initiatorStartLocation["shortStr"]

再去传入:

        db.session.add(newInitiatorStartLocation)
        db.session.flush()
        # after flush, can got generated location id
        newTask = Task(
            itemType = itemType,
            initiatorId = userId,
            initiatorStartLocationId = newInitiatorStartLocation.id
        )
        db.session.add(newTask)

就可以了。

【总结】

此处是不小心,把新建一个对象中,所要传递的参数,应该是一个(Location)对象,但是误传入了一个dict变量。

解决办法是:

新建对应的(Location)对象,然后再去传递对应的对象即可。

注:此处是传入对应的Location对象的id

内部是通过:

class Location(db.Model):
    __tablename__ = ‘locations’
    id = db.Column(db.String(64), primary_key=True, default = generateUUID("location-"), nullable=False)
class Task(db.Model):
    __tablename__ = ‘tasks’
    initiatorStartLocationId = db.Column(db.String(64), db.ForeignKey("locations.id"))
    initiatorStartLocation = db.relationship("Location", foreign_keys=[initiatorStartLocationId])

从而自动可以通过:

newTask.initiatorStartLocation

就获取到对应的Location对象了。



发表评论

电子邮件地址不会被公开。 必填项已用*标注

无觅相关文章插件,快速提升流量