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
看错了。
实际上是:
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对象了。
转载请注明:在路上 » 【已解决】Flask-Restful的api出错:AttributeError dict object has no attribute _sa_instance_state