无法在 SQLAlchemy 烧瓶中的结果对象上设置属性

Fly*_*ger 4 python sqlalchemy flask-sqlalchemy

我遇到的烧瓶SQLAlchemy的一个问题,我可以设置对象的属性place_collections,但是当我想设置为对象属性的地方,发生了错误:

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
Run Code Online (Sandbox Code Playgroud)

如何设置加入搜索对象的属性,有人可以帮助我吗?

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)
Run Code Online (Sandbox Code Playgroud)

它们都是class 'flask_sqlalchemy.BaseQuery'类型。


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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)

模型

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)
Run Code Online (Sandbox Code Playgroud)

Sup*_*oot 8

place_collections = Place.query.filter_by(county='BKK')将返回一个Place对象集合。这类似于session.query(Place).filter_by(county='BKK')普通的 SQLAlchemy。

但是,来自 SQLAlchemy文档

查询还接受 ORM 检测的描述符作为参数。任何时候将多个类实体或基于列的实体表示为 query() 函数的参数,返回结果表示为元组

关键是当您指定要查询的特定列时,就像您在此处所做的那样:

places = db.session.query(Place.roll_number, Place.name,
    Place.website, Place.address, Place.distance).\
    outerjoin(Rank, Rank.place_id == Place.place_id)
Run Code Online (Sandbox Code Playgroud)

结果表示为 的集合tuples

我的第一印象是can't set attribute尝试将属性值分配给 a 时收到一条奇怪的错误消息tuple,因此我尝试了它:

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

这不是您收到的错误消息。

所以我执行了一个类似于你的第二个查询(模型只是我打开的一个项目的东西):

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

是的,所以我们没有得到一个元组,我们得到了一个sqlalchemy.util._collections.result对象。但..

>>> issubclass(type(a_result), tuple)
True
Run Code Online (Sandbox Code Playgroud)

所以,sqlalchemy.util._collections.result 一个类型tuple

如果我们尝试为不是查询列之一的属性分配一个值:

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

该错误消息与我们之前将属性分配给普通tuple.

那么为什么您会收到不同的错误消息?该result对象实际上更像是一个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
Run Code Online (Sandbox Code Playgroud)

这与您收到的错误消息相同。

因此,该sqlalchemy.util._collections.result对象支持列名的属性访问,但由于它tuple仍然是不可变的,因此您无法写入这些属性。

要修复您的特定错误(除非您出于某种原因专门查询这些列)将您的places查询更改为:

places = db.session.query(Place).outerjoin(Rank, Rank.place_id == Place.place_id)
Run Code Online (Sandbox Code Playgroud)