Python `Query.count()`炼金术和多重绑定带来了麻烦 摘要

Python `Query.count()`炼金术和多重绑定带来了麻烦 摘要,python,flask-sqlalchemy,Python,Flask Sqlalchemy,我在炼金术中使用多重绑定时遇到问题。特别是,查询对象上的count方法似乎不起作用 详情 我的Flask应用程序在PostgreSQL数据库上工作。此外,它还从MySQL上运行的遗留安装中检索数据 为了方便使用,我为MySQL数据库使用了第二个Flask SQLAlchemy绑定,并通过反射设置了类。查询通常可以正常工作,但使用count会导致sqlalchemy.exc.ProgrammingError,即相应的表不存在 密码 myapp/app.py: myapp/model.py: 为便于

我在炼金术中使用多重绑定时遇到问题。特别是,查询对象上的count方法似乎不起作用

详情 我的Flask应用程序在PostgreSQL数据库上工作。此外,它还从MySQL上运行的遗留安装中检索数据

为了方便使用,我为MySQL数据库使用了第二个Flask SQLAlchemy绑定,并通过反射设置了类。查询通常可以正常工作,但使用count会导致sqlalchemy.exc.ProgrammingError,即相应的表不存在

密码 myapp/app.py:

myapp/model.py:

为便于阅读,错误堆栈跟踪中的文件路径示例缩短:

% python
Python 2.7.6 (default, Dec  2 2013, 11:07:48)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from myapp.model import Topics
>>> len(Topics.query.all())
10162
>>> Topics.query.count()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "…/sqlalchemy/orm/query.py", line 2573, in count
    return self.from_self(col).scalar()
  File "…/sqlalchemy/orm/query.py", line 2379, in scalar
    ret = self.one()
  File "…/sqlalchemy/orm/query.py", line 2348, in one
    ret = list(self)
  File "…/sqlalchemy/orm/query.py", line 2391, in __iter__
    return self._execute_and_instances(context)
  File "…/sqlalchemy/orm/query.py", line 2406, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "…/sqlalchemy/engine/base.py", line 717, in execute
    return meth(self, multiparams, params)
  File "…/sqlalchemy/sql/elements.py", line 317, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "…/sqlalchemy/engine/base.py", line 814, in _execute_clauseelement
    compiled_sql, distilled_params
  File "…/sqlalchemy/engine/base.py", line 927, in _execute_context
    context)
  File "…/sqlalchemy/engine/base.py", line 1076, in _handle_dbapi_exception
    exc_info
  File "…/sqlalchemy/util/compat.py", line 185, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "…/sqlalchemy/engine/base.py", line 920, in _execute_context
    context)
  File "…/sqlalchemy/engine/default.py", line 425, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "smf_topics" does not exist
LINE 3: FROM smf_topics) AS anon_1
             ^
 'SELECT count(*) AS count_1 \nFROM (SELECT smf_topics.id_topic AS smf_topics_id_topic, […] \nFROM smf_topics) AS anon_1' {}
以及运行脚本时的输出:

1. 10400
2. 10400
Traceback (most recent call last):
  File "./test.py", line 35, in <module>
    print('3. {}'.format(topic_class.query.count()))
  File "…/sqlalchemy/orm/query.py", line 2640, in count
    return self.from_self(col).scalar()
  File "…/sqlalchemy/orm/query.py", line 2426, in scalar
    ret = self.one()
  File "…/sqlalchemy/orm/query.py", line 2395, in one
    ret = list(self)
  File "…/sqlalchemy/orm/query.py", line 2438, in __iter__
    return self._execute_and_instances(context)
  File "…/sqlalchemy/orm/query.py", line 2453, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "…/sqlalchemy/engine/base.py", line 729, in execute
    return meth(self, multiparams, params)
  File "…/sqlalchemy/sql/elements.py", line 322, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "…/sqlalchemy/engine/base.py", line 826, in _execute_clauseelement
    compiled_sql, distilled_params
  File "…/sqlalchemy/engine/base.py", line 958, in _execute_context
    context)
  File "…/sqlalchemy/engine/base.py", line 1159, in _handle_dbapi_exception
    exc_info
  File "…/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "…/sqlalchemy/engine/base.py", line 951, in _execute_context
    context)
  File "…/sqlalchemy/engine/default.py", line 436, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "smf_topics" does not exist
LINE 3: FROM smf_topics) AS anon_1
             ^
 'SELECT count(*) AS count_1 \nFROM (SELECT smf_topics.id_topic AS smf_topics_id_topic, […] \nFROM smf_topics) AS anon_1' {}

下面是它的工作原理。^^^关键是使用db.reflect,然后提供db.Model.metadata作为新创建的类的元数据:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/igor'
app.config['SQLALCHEMY_BINDS'] = {
    'smf': 'mysql://myuser:mypass@localhost/my_db',
}
db = SQLAlchemy(app)
db.reflect(bind='smf', app=app)
topic_class = type(db.Model)('Topic', (db.Model,), {
    '__bind_key__': 'smf',
    '__table__': db.Model.metadata.tables['smf_topics'],
    '__tablename__': 'smf_topics',
    '__module__': __name__,
    'metadata': db.Model.metadata,
})

if __name__ == '__main__':
    print('1. {}'.format(len(topic_class.query.all())))
    print('2. {}'.format(topic_class.query.count()))

看起来像个虫子。您是否使用最新版本的flask/sqlalchemy?如果已经报告了类似的情况,您是否已经在bug数据库中搜索了这些库?因为如果没有,我会继续报告。我还想通过查看query.all和query.count执行各自查询的方式之间的差异来找出原因。这有点像打印SQL查询,您是否尝试过直接执行它?而不是更改元,您是否尝试在定义的模型中指定_绑定_密钥_;了?Niklas B:我在问题跟踪器中找不到这个bug。深入研究SQLAlchemy的query.all和query.count超出了我的能力。我将把它归档在Flask SQLAlchemy的tracker.aisbaa中:直接执行SQL非常好!
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData

# Application setup
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/igor'
app.config['SQLALCHEMY_BINDS'] = {
    'smf': 'mysql://myuser:mypass@localhost/my_db',
}
db = SQLAlchemy(app)

# Database reflection
smf_meta = MetaData(bind=db.get_engine(app, bind='smf'))
smf_meta.reflect()
topic_class = type(db.Model)('Topic', (db.Model,), {
    '__bind_key__': 'smf',
    '__tablename__': 'smf_topics',
    '__table__': smf_meta.tables['smf_topics'],
})

# Conventional model class
class Topic(db.Model):
    __bind_key__ = 'smf'
    __tablename__ = 'smf_topics'
    id_topic = db.Column(db.Integer, primary_key=True)
    num_replies = db.Column(db.Integer, nullable=False, default=0)

# Run it
if __name__ == '__main__':
    print('1. {}'.format(Topic.query.count()))
    print('2. {}'.format(len(topic_class.query.all())))
    print('3. {}'.format(topic_class.query.count()))
1. 10400
2. 10400
Traceback (most recent call last):
  File "./test.py", line 35, in <module>
    print('3. {}'.format(topic_class.query.count()))
  File "…/sqlalchemy/orm/query.py", line 2640, in count
    return self.from_self(col).scalar()
  File "…/sqlalchemy/orm/query.py", line 2426, in scalar
    ret = self.one()
  File "…/sqlalchemy/orm/query.py", line 2395, in one
    ret = list(self)
  File "…/sqlalchemy/orm/query.py", line 2438, in __iter__
    return self._execute_and_instances(context)
  File "…/sqlalchemy/orm/query.py", line 2453, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "…/sqlalchemy/engine/base.py", line 729, in execute
    return meth(self, multiparams, params)
  File "…/sqlalchemy/sql/elements.py", line 322, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "…/sqlalchemy/engine/base.py", line 826, in _execute_clauseelement
    compiled_sql, distilled_params
  File "…/sqlalchemy/engine/base.py", line 958, in _execute_context
    context)
  File "…/sqlalchemy/engine/base.py", line 1159, in _handle_dbapi_exception
    exc_info
  File "…/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "…/sqlalchemy/engine/base.py", line 951, in _execute_context
    context)
  File "…/sqlalchemy/engine/default.py", line 436, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (ProgrammingError) relation "smf_topics" does not exist
LINE 3: FROM smf_topics) AS anon_1
             ^
 'SELECT count(*) AS count_1 \nFROM (SELECT smf_topics.id_topic AS smf_topics_id_topic, […] \nFROM smf_topics) AS anon_1' {}
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://localhost/igor'
app.config['SQLALCHEMY_BINDS'] = {
    'smf': 'mysql://myuser:mypass@localhost/my_db',
}
db = SQLAlchemy(app)
db.reflect(bind='smf', app=app)
topic_class = type(db.Model)('Topic', (db.Model,), {
    '__bind_key__': 'smf',
    '__table__': db.Model.metadata.tables['smf_topics'],
    '__tablename__': 'smf_topics',
    '__module__': __name__,
    'metadata': db.Model.metadata,
})

if __name__ == '__main__':
    print('1. {}'.format(len(topic_class.query.all())))
    print('2. {}'.format(topic_class.query.count()))