No se puede establecer el atributo en los objetos de resultado en el matraz SQLAlchemy

Encuentro un problema con Flask-SQLAlchemy, puedo establecer el atributo de los objetos en place_collections , pero cuando quiero establecer el atributo para los objetos en lugares , ocurrió un error:

Traceback (most recent call last): File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 2309, in __call__ return self.wsgi_app(environ, start_response) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/werkzeug/contrib/fixers.py", line 152, in __call__ return self.app(environ, start_response) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app response = self.handle_exception(e) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app response = self.full_dispatch_request() File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb) File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request rv = self.dispatch_request() File "/Users/user/PycharmProjects/website/venv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/Users/user/Document/Python/Test/Code/app/main/views.py", line 108, in index place.distance = round(distance_computing, 1) AttributeError: can't set attribute 

¿Cómo puedo establecer el atributo para unir el objeto de búsqueda? ¿Podría alguien ayudarme?

 place_collections = Place.query.filter_by(county='BKK') places = db.session.query(Place.roll_number, Place.name, Place.website, Place.address, Place.distance) .outerjoin(Rank, Rank.place_id == Place.place_id) 

Ambos son del tipo ‘flask_sqlalchemy.BaseQuery’ de clase.


 for place in place_collections: distance_computing = Place.distance_calculator(float(place.lat), float(place.lng), data['lat'], data['lng']) place.distance = round(distance_computing, 1) 

 for place in places: distance_computing = Place.distance_calculator(float(school.lat), float(school.lng), data['lat'], data['lng']) place.distance = round(distance_computing, 1) 

Modelo

 class Rank(db.Model): __tablename__ = 'rank' place_id = db.Column(db.String(50)) name = db.Column(db.String(255), nullable=False, primary_key=True) rank = db.Column(db.Integer) class Place(db.Model): _tablename_ = 'school' place_id = db.Column(db.String(50), primary_key=True) roll_number = db.Column(db.String(50)) name = db.Column(db.String(255), nullable=False) address = db.Column(db.String(255)) distance = db.Column(db.String(50)) rank = db.relationship('Rank',backref=db.backref('roll_number1'), lazy=True, uselist=False) 

place_collections = Place.query.filter_by(county='BKK') le devolverá una colección de objetos Place . Esto es análogo a session.query(Place).filter_by(county='BKK') en SQLAlchemy de vainilla simple.

Sin embargo, desde la documentación de SQLAlchemy:

La consulta también acepta descriptores instrumentados por ORM como argumentos. Cada vez que varias entidades de clase o entidades basadas en columnas se expresan como argumentos a la función query (), el resultado devuelto se expresa como tuplas

El punto clave es que cuando especifique columnas específicas para consultar, como lo ha hecho aquí:

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

El resultado se expresa como una colección de tuples .

Mi primera impresión fue que can't set attribute recibió un mensaje de error extraño al intentar asignar un valor de atributo a una tuple , así que lo intenté:

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

Ese no es el mensaje de error que recibió.

Entonces realicé una consulta similar a la segunda (el modelo es simplemente algo de un proyecto que tenía abierto):

 >>> q = session.query(Racecard.id, Racecard.meeting) >>> a_result = q[0] >>> type(a_result)  

Bien, entonces no estamos obteniendo una tupla, obtenemos un objeto sqlalchemy.util._collections.result . Pero..

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

Por lo tanto, el sqlalchemy.util._collections.result es un tipo de tuple .

Si intentamos asignar un valor a un atributo que no es una de las columnas que se consultaron:

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

Ese mensaje de error es muy similar al que recibimos antes cuando asignamos un atributo a una tuple simple.

Entonces, ¿por qué recibiste un mensaje de error diferente? El objeto de result es en realidad más como una namedtuple :

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

Que es el mismo mensaje de error que está recibiendo.

Por lo tanto, el objeto sqlalchemy.util._collections.result admite el acceso a los atributos de los nombres de columna, pero como es una tuple , sigue siendo inmutable, por lo que no puede escribir en esos atributos.

Para corregir su error específico (a menos que haya alguna razón por la que estaba consultando específicamente solo esas columnas), cambie su consulta de places a:

 places = db.session.query(Place).outerjoin(Rank, Rank.place_id == Place.place_id)