I encounter a problem with Flask-SQLAlchemy, I can set the attribute of the objects in place_collections, but when I want to set the attribute for objects in places, an error occurred:
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
How can I set the attribute for join search object, could anyone help me?
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)
Both of them are class 'flask_sqlalchemy.BaseQuery' type.
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)
Model
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')
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With