从表命名项创建自动映射模型的新实例时发生类型错误



我有一个数据库,其中有一个名为"项目":

import sqlite3
stmt = """CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)"""
conn = sqlite3.connect('test20210101.db')
conn.execute(stmt)

我使用SQLAlchemy的自动映射功能将表映射到一个模型类:

import sqlalchemy as sa
from sqlalchemy.ext.automap import automap_base
engine = sa.create_engine('sqlite:///test20210101.db')
Base = automap_base()
Base.prepare(engine, reflect=True)
Item = Base.classes.items

但是,如果我尝试创建一个新项目,我会得到一个TypeError:

>>> new_item = Item(name='foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: items() got an unexpected keyword argument 'name'

同样,尝试使用自动映射模型查询数据库失败:

>>> items = session.query(Item).all()
Traceback (most recent call last):
<lots of traceback>
sqlalchemy.exc.ArgumentError: Column expression or FROM clause expected, got ('items', <class 'sqlalchemy.ext.automap.items'>).

类似的代码适用于其他表,这里发生了什么?

正如TypeError的提出所表明的那样,问题是Item不是我们所期望的自动映射模型。实际上它是一个方法对象:

>>> type(Item)
<class 'method'>
>>> Item
<bound method Properties.items of <sqlalchemy.util._collections.Properties object at 0x7fb088f48fa0>>

问题是Base.classes公开了类似于字典的API,而Base.classes.items是API的items方法,而不是自动映射的对象*。

至少有两种方法可以解决这个名称冲突:

  • 使用__getitem__访问自动映射对象

    >>> Item = Base.classes['items']
    >>> Item
    <class 'sqlalchemy.ext.automap.items'>
    
  • 定义一个自定义函数,在准备Base时将表名映射到类名

    >>> def map_names(base, tablename, table):
    ...     return 'my_items' if tablename == 'items' else tablename
    ...    
    >>> Base = automap_base()
    >>> Base.prepare(engine, reflect=True, classname_for_table=map_names)
    >>> Item = Base.classes.my_items
    >>> Item
    <class 'sqlalchemy.ext.automap.my_items'>
    

*因此,其他与dict相关的名称也会出现同样的问题,例如keysvalues等。

您导入的是文件,而不是类别Item

更改:

import Item

from Item import Item

最新更新