Can't set attribute on result objects in SQLAlchemy flask

≯℡__Kan透↙ 提交于 2019-11-27 09:50:13

place_collections = Place.query.filter_by(county='BKK') will return you a collection of Place objects. This is analogous to session.query(Place).filter_by(county='BKK') in plain vanilla SQLAlchemy.

However, from the SQLAlchemy docs:

The Query also accepts ORM-instrumented descriptors as arguments. Any time multiple class entities or column-based entities are expressed as arguments to the query() function, the return result is expressed as tuples

The key point being that when you specify specific columns to query as you have done here:

places = db.session.query(Place.roll_number, Place.name,
    Place.website, Place.address, Place.distance).\
    outerjoin(Rank, Rank.place_id == Place.place_id)

the result is expressed as a collection of tuples.

My first impression was that can't set attribute was a strange error message to receive from trying to assign an attribute value to a tuple, so I tried it:

>>> t = tuple()
>>> t.attribute = 9
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'attribute'

That's not the error message that you received.

So I performed a query similar to your second one (the model is just something from a project that I had open):

>>> q = session.query(Racecard.id, Racecard.meeting)
>>> a_result = q[0]
>>> type(a_result)
<class 'sqlalchemy.util._collections.result'>

Right, so we aren't getting a tuple, we get a sqlalchemy.util._collections.result object. But..

>>> issubclass(type(a_result), tuple)
True

So, the sqlalchemy.util._collections.result is a type of tuple.

If we try to assign a value to an attribute that is not one of the columns that were queried:

>>> a_result.newattribute = 'something'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'result' object has no attribute 'newattribute'

That error message is very similar to the one that we got before when assigning an attribute to a plain tuple.

So why did you get a different error message? The result object is actually more like a namedtuple:

>>> from collections import namedtuple
>>> Racecard = namedtuple('Racecard', 'id, meeting')
>>> rc = Racecard(1, 'Doomben')
>>> rc.meeting = 'Eagle Farm'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Which is the same error message that you are getting.

So, the sqlalchemy.util._collections.result object supports attribute access of the column names, but as it is a tuple it is still immutable, so you cannot write to those attributes.

To fix your specific error (unless there was some reason that you were specifically querying only those columns) change your places query to:

places = db.session.query(Place).outerjoin(Rank, Rank.place_id == Place.place_id)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!