简体   繁体   中英

TypeError creating new instance of automapped model from table named items

I have a database with a table named "items":

import sqlite3

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

I use SQLAlchemy's automap feature to map the table to a model class:

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

However if I try to create a new item, I get a 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'

Likewise attempts to query the database using the automapped model fail:

>>> 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'>).

Similar code works for other tables, what's going on here?

As the raising of TypeError suggests, the problem is that Item is not an automapped model as we would expect. In fact it's a method object:

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

The problem is that Base.classes exposes a dictionary-like API, and Base.classes.items is the API's items method rather than the automapped object*.

There are at least two ways to work around this name collision:

  • access the automapped object using __getitem__

     >>> Item = Base.classes['items'] >>> Item <class 'sqlalchemy.ext.automap.items'>
  • define a custom function to map table names to class names when preparing the 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'>

* So the same problem occurs for other dict-related names, for example keys , values etc.

You are importing the file not the class Item

change:

import Item

to

from Item import Item

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM