检查不存在的可选表

时间:2012-05-01 09:49:16

标签: python sqlalchemy pyramid

我正在使用SQLAlchemy + Pyramid来操作我的数据库。但是,有一些可选表格并不总是存在于DB中。因此,在查询它们时,我尝试使用NoSuchTableError

来捕获这些情况
try:
    x = session.query(ABC.name.label('sig_name'),func.count('*').label('count_')).join(DEF).join(MNO).filter(MNO.relevance >= relevance_threshold).group_by(DEF.signature).order_by(desc('count_')).all()[:val]
except NoSuchTableError:
    x = [-1,]

但是在执行此语句时,我得到了一个ProgrammingError

ProgrammingError: (ProgrammingError) (1146, "Table 'db.mno' doesn't exist")

为什么SQLAlchemy会引发更一般的ProgrammingError而不是更具体的NoSuchTableError?如果这确实是预期的行为,我如何确保应用程序显示正确的信息,具体取决于表格是否存在?

EDIT1

由于这是我的webapp的一部分,因此DB的模型位于models.py(在我的金字塔webapp下)。我的.ini文件中有一个设置,要求用户选择是否有其他表可用。但不信任用户,我希望能够检查自己(在视图中)表是否存在。有争议的表类似于(在models.py

class MNO(Base):
    __tablename__="mno"
    id=Column(Integer,primary_key=True,autoincrement=True)
    sid=Column(Integer)
    cid=Column(mysql.MSInteger(unsigned=True))
    affectability=Column(Integer)
    cvss_base=Column(Float)
    relevance=Column(Float)
    __table_args__=(ForeignKeyConstraint(['sid','cid',],['def.sid','def.cid',]),UniqueConstraint('sid','cid'),)

如何以及在何处进行检查以便可以设置变量(最好在应用程序设置期间),告诉我表格是否存在?

注意:在这种情况下,我将不得不尝试...而不是“请求原谅”

1 个答案:

答案 0 :(得分:6)

根据sqlalchemy文档,只有在“SQLAlchemy [is]要求从数据库加载表的定义但该表不存在时才会抛出NoSuchTableError。”您可以尝试加载表的定义,捕获错误,然后执行查询。

如果你想通过“请求原谅”来做事:

try:
    table = Table(table_name, MetaData(engine)) 
except NoSuchTableError:
    pass

或者,您可以检查表是否存在:

修改

更好的是,为什么不使用has_table method

if engine.dialect.has_table(connection, table_name):
    #do your crazy query

为什么不首先使用Inspector来获取表名?

也许是这样的:

from sqlalchemy import create_engine
from sqlalchemy.engine import reflection
#whatever code you already have
engine = create_engine('...')
insp = reflection.Inspector.from_engine(engine)
table_name = 'foo'
table_names = insp.get_table_names()
if table_name in table_names:
    x = session.query(ABC.name.label('sig_name'),func.count('*').label('count_')).join(DEF).join(MNO).filter(MNO.relevance >= relevance_threshold).group_by(DEF.signature).order_by(desc('count_')).all()[:val]