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

Die*_*ira 18 python postgresql sqlalchemy python-2.7

我有SQL Alchemy的问题,在尝试创建数据库时,我得到:

"sqlalchemy.exc.NoReferencedTableError:与列'estate_agent.person_id'关联的外键无法找到用于生成目标列'id'的外键的表'person'"

元数据:

db = create_engine('postgresql+psycopg2:...//')
meta = MetaData()
meta.bind = db
Run Code Online (Sandbox Code Playgroud)

人员表:

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')
Run Code Online (Sandbox Code Playgroud)

错误表:

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')
Run Code Online (Sandbox Code Playgroud)

普通表(通常创建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')
Run Code Online (Sandbox Code Playgroud)

创作电话:

meta.create_all(checkfirst=True)
Run Code Online (Sandbox Code Playgroud)

完整的错误日志:

回溯(最近一次调用最后一次):文件"database_client.py",第159行,在meta.create_all(checkfirst = True)文件"/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)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py",第1245行,在_run_visitor**kwargs).traverse_single(element)文件"/ usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第120行,在traverse_single中返回meth(obj,**kw)文件"/usr/local/lib/python2.7/dist- packages/sqlalchemy/sql/ddl.py",第699行,in visit_metadata collection = [t for sort in sort(tables)File"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py",第862行,在sort_tables {'foreign_key':visit_foreign_key })文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第256行,在遍历返回traverse_using(iterate(obj,opts),obj,visitor)文件"/ usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第247行,在traverse_using meth(target)文件中"/usr/local/lib/python2.7/dist-packages/sqlalchemy /sql/ddl.py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",第725行,在在/ sort {'foreign_key':visit_foreign_key})文件"/usr/local/lib/python2.7 dist-packages/sqlalchemy/sql/visitors.py",第256行,在遍历返回traverse_using(iterate(obj,opts),obj,visitor)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy /sql/visitors.py",第247行,在traverse_using meth(target)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",第725行,in在/ sort {'foreign_key':visit_foreign_key})文件"/usr/local/lib/python2.7 dist-packages/sqlalchemy/sql/visitors.py",第256行,在遍历返回traverse_using(iterate(obj,opts),obj,visitor)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy /sql/visitors.py",第247行,在traverse_using meth(target)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",第725行,in/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第256行,在遍历返回traverse_using(iterate(obj,opts),obj,visitor)文件"/ usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第247行,在traverse_using meth(target)文件中"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl .py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",第725行,在/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第256行,在遍历返回traverse_using(iterate(obj,opts),obj,visitor)文件"/ usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py",第247行,在traverse_using meth(target)文件中"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl .py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py",第725行,在/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist -packages/sqlalchemy/util/langhelpers.py",第725行,in/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py",第853行,在visit_foreign_key中parent_table = fkey.column.table文件"/usr/local/lib/python2.7/dist -packages/sqlalchemy/util/langhelpers.py",第725行,in得到 obj.dict [self.name ] = result = self.fget(obj)文件"/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/schema.py",第1720行,在列tablekey中)sqlalchemy.exc.NoReferencedTableError:与列'estate_agent.person_id'相关联的外键无法找到用于生成外键以定位列'id'的表'person'

Mat*_*sen 21

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

Column('person_id', Integer, ForeignKey(tbl_person.c.id), primary_key=True)
Run Code Online (Sandbox Code Playgroud)

  • @Icyh 迟到了,但它有效,因为您必须导入 `Table` 对象,这意味着它实际上是创建的。我敢打赌,在原始代码中还没有创建 `tbl_person`,因此字符串查找失败,因为 `MetaData` 不包含它。 (5认同)

Jak*_*ski 12

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


swi*_*mer 12

尽管投票最高的答案解决了问题,但用对象替换字符串会迫使您按特定顺序定义表(对于非常大的数据库来说,这可能很重要)。来自SQLAlchemy 文档

使用字符串的优点是,[不同表]之间的 in-python 链接仅在第一次需要时才会解析,因此表对象可以轻松地分布在多个模块中并以任何顺序定义。

您可以通过将架构传递到ForeignKey. 例如,不要这样做:

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')
Run Code Online (Sandbox Code Playgroud)

一个人可以做:

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


Ham*_*med 8

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

children = relationship("Child")
Run Code Online (Sandbox Code Playgroud)

否则:SQLAlchemy - Classic Mapper

也试着看看这里(SO)也许有帮助.


小智 7

结论

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

def upgrade(migrate_engine):

    meta.bind = migrate_engine

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

    aggregate_metadata.create()
    aggregate_hosts.create()
Run Code Online (Sandbox Code Playgroud)

描述

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

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

例如:

# 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()
Run Code Online (Sandbox Code Playgroud)
# 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()
Run Code Online (Sandbox Code Playgroud)

根本原因

让我们定位到抛出异常的位置

  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'
Run Code Online (Sandbox Code Playgroud)

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

# 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              )
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  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'
Run Code Online (Sandbox Code Playgroud)

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

# 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              )
Run Code Online (Sandbox Code Playgroud)

没关系!