SQLalchemy找不到用于创建外键的表

时间:2015-01-20 13:52:11

标签: python postgresql python-2.7 sqlalchemy

我在使用SQL Alchemy时遇到问题,在尝试创建数据库时,我得到:

  

" sqlalchemy.exc.NoReferencedTableError:与之关联的外键   栏' estate_agent.person_id'找不到桌子的人#39;同   哪个生成外键以定位列' id'"

元数据:

db = create_engine('postgresql+psycopg2:...//')
meta = MetaData()
meta.bind = db

人员表:

tbl_person = Table(
   'person', meta,
   Column('id', Integer, Sequence('seq_person_id'), primary_key=True),
   Column('name', String(100), unique=True, nullable = False),
   Column('password', String(40), nullable = False),
   Column('person_type_id', Integer, ForeignKey("person_type.id"), nullable = False),
   Column('register_date', DateTime, default = datetime.now),
   Column('pendencies', String(200)),
   Column('active', Boolean, default = True),
   schema = 'public')

错误表:

tbl_estate_agent = Table(
   'estate_agent', meta,
   Column('person_id', Integer, ForeignKey("person.id"), primary_key = True),
   Column('prize_range_id', Integer, ForeignKey("prize_range.id"), nullable = False),
   schema = 'public')

普通表(通常创建fk)

tbl_person_agent = Table(
   'person_agent', meta,
   Column('person_id', Integer, ForeignKey("person.id"), primary_key = True),
   Column('prize_range_id', Integer, ForeignKey("prize_range.id"), nullable = False),
   schema = 'public')

创建电话:

meta.create_all(checkfirst=True)

完整的错误日志:

  

Traceback(最近一次调用最后一次):File" database_client.py",line   159,在       meta.create_all(checkfirst = True)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/schema.py",   第3404行,在create_all中       tables = tables)文件" /usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py",   第1616行,在_run_visitor中       conn._run_visitor(visitorcallable,element,** kwargs)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py",   第1245行,在_run_visitor中       ** kwargs)。traverse_single(element)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",   第120行,在traverse_single中       return meth(obj,** kw)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py" ;, line   699,在visit_metadata中       collection = [t for sort_tables(tables)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py" ;, line   862,在sort_tables中       {' foreign_key&#39 ;: visit_foreign_key})文件" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",   第256行,遍历       return traverse_using(iterate(obj,opts),obj,visitor)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",   第247行,在traverse_using中       meth(target)File" /usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py" ;, line   853,在visit_foreign_key中       parent_table = fkey.column.table文件" /usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",   第725行,获取       obj。 dict [self。 name ] = result = self.fget(obj)File" /usr/local/lib/python2.7/dist-packages /sqlalchemy/sql/schema.py" ;,   第1720行,在列表键中)   sqlalchemy.exc.NoReferencedTableError:与之关联的外键   栏' estate_agent.person_id'找不到桌子的人#39;同   哪个生成外键以定位列' id'

4 个答案:

答案 0 :(得分:15)

解决方案是用实际列替换字符串:

Column('person_id', Integer, ForeignKey(tbl_person.c.id), primary_key=True)

答案 1 :(得分:8)

通过在我的parent表中添加以下行解决了我的问题。在声明的情况下:

children = relationship("Child")

否则:SQLAlchemy - Classic Mapper

同时尝试查看here (SO),也许有帮助。

答案 2 :(得分:1)

在声明式的情况下,我通过简单地导入“无法找到”的类来解决了这个问题。

答案 3 :(得分:0)

结论

这个异常是因为MetaData实例中没有父表的记录,需要在DB中检索该表。 调用 MetaData 类的“reflect”函数来获取数据库中所有存在的表。应该这样使用

def upgrade(migrate_engine):

    meta.bind = migrate_engine

    meta.reflect() # <------ Obtain all tables here.

    aggregate_metadata.create()
    aggregate_hosts.create()

说明

一个表与另一个有外键关联的表位于不同的文件中。 在这种情况下,sqlalchemy在创建表时会找不到对应的表,如下图:

<块引用>

sqlalchemy.exc.NoReferencedTableError: 与列“aggregate_metadata.aggregate_id”关联的外键找不到表“聚合”,用于生成目标列“id”的外键

例如:

# File 002_Add_aggregates_table.py
# ========================================
...

meta = MetaData()

aggregates = Table('aggregates', meta,
    ...
    Column('id', Integer, primary_key=True, nullable=False),
    mysql_engine='InnoDB',
    mysql_charset='utf8'
)

def upgrade(migrate_engine):
    meta.bind = migrate_engine
    aggregates.create()
# File 003_Add_aggregate_metadata_hosts.py
# ========================================
...

meta = MetaData()

aggregate_metadata = Table('aggregate_metadata', meta,
    ...
    Column('aggregate_id', Integer, ForeignKey('aggregates.id'), # <------ ForeignKey
           nullable=False),
    mysql_engine='InnoDB',
    mysql_charset='utf8'
    )

def upgrade(migrate_engine):

    meta.bind = migrate_engine
    aggregate_metadata.create()

根本原因

定位到抛出异常的点

  File "/opt/xxx/.local/lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 1113, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/opt/xxx/.local/lib/python3.6/site-packages/sqlalchemy/sql/schema.py", line 2394, in column
    tablekey,
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'aggregate_metadata.aggregate_id' could not find table 'aggregates' with which to generate a foreign key to target column 'id'

我们可以找到对应的代码并进行调试:

# File: sqlalchemy/sql/schema.py
2358     def column(self):
            ...
2371
2372        if isinstance(self._colspec, util.string_types):
2373
2374           parenttable, tablekey, colname = self._resolve_col_tokens()

# =========> BeginDebug
2375           raise Exception(
2376               'imgrass->\n'
2377               '  - parenttable: %s\n'
2378               '  - parenttable.metadata: %s\n'
2379               '  - tablekey: %s\n'
2380               '  - colname: %s' % (
2381                   parenttable,
2382                   parenttable.metadata,
2383                   tablekey,
2384                   colname
2385                   )
2386               )
# =========> EndDebug

2387
2388           if tablekey not in parenttable.metadata:
2389              raise exc.NoReferencedTableError(
2390                 "Foreign key associated with column '%s' could not find "
2391                 "table '%s' with which to generate a "
2392                 "foreign key to target column '%s'"
2393                 % (self.parent, tablekey, colname),
2394                 tablekey,
2395              )

然后我们可以得到以下异常:

Exception: imgrass->
  - parenttable: aggregate_metadata
  - parenttable.metadata: MetaData(bind=Engine(mysql+pymysql://imgrass:***@172.17.0.1/demo))
  - tablekey: aggregates
  - colname: id

所以,parenttable.metadataMetaData 类的一个实例,tablekey 是一个表名。 我们可以合理地猜测表aggregates 应该包含在类MetaData 的实例中。 考虑到这个表的定义在另一个文件中,并且MetaData实例有DB(bind=xxx)的连接方式,MetaData类中应该有一个函数获取数据库中的所有表。

在MetaData中,我们可以找到这个函数

# File: sqlalchemy/sql/schema.py

class MetaData(SchemaItem):
    ...

    def reflect(...):
        r"""Load all available table definitions from the database.
        ...

从它的描述中,我们可以猜到它的功能,让我们将它应用到我的脚本中:

# File 003_Add_aggregate_metadata_hosts.py
# ========================================
...

def upgrade(migrate_engine):

    meta.bind = migrate_engine

# ==================> BeginUpdate
    meta.reflect()
# ==================> EndUpdate

    aggregate_metadata.create()
    aggregate_hosts.create()

没关系!