[英]SQLalchemy not find table for creating foreign key
I have a problem with SQL Alchemy, while trying to create a database, i get:我在使用 SQL Alchemy 时遇到问题,在尝试创建数据库时,我得到:
"sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'estate_agent.person_id' could not find table 'person' with which to generate a foreign key to target column 'id'"
Meta datas:元数据:
db = create_engine('postgresql+psycopg2:...//')
meta = MetaData()
meta.bind = db
Person table:人员表:
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')
Bug Table:错误表:
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')
Normal table (creating normally the fk)正常表(正常创建 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')
Creation Call:创作召唤:
meta.create_all(checkfirst=True)
Complete error log:完整的错误日志:
Traceback (most recent call last):
File "database_client.py", line 159, in <module>
meta.create_all(checkfirst=True)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/schema.py", line 3404, in create_all
tables=tables)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1616, in _run_visitor
conn._run_visitor(visitorcallable, element, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1245, in _run_visitor
**kwargs).traverse_single(element)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py", line 120, in traverse_single
return meth(obj, **kw)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py", line 699, in visit_metadata
collection = [t for t in sort_tables(tables)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py", line 862, in sort_tables
{'foreign_key': visit_foreign_key})
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py", line 256, in traverse
return traverse_using(iterate(obj, opts), obj, visitors)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/visitors.py", line 247, in traverse_using
meth(target)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/ddl.py", line 853, in visit_foreign_key
parent_table = fkey.column.table File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py", line 725, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/sql/schema.py", line 1720, in column tablekey)
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'estate_agent.person_id' could not find table 'person' with which to generate a foreign key to target column 'id'
解决方案是用实际列替换字符串:
Column('person_id', Integer, ForeignKey(tbl_person.c.id), primary_key=True)
By adding the following line to my parent
table solved my problem.通过将以下行添加到我的
parent
表解决了我的问题。 In case of Declarative:如果是声明式:
children = relationship("Child")
Otherwise: SQLAlchemy - Classic Mapper否则: SQLAlchemy - 经典映射器
Also try to have a look in here (SO) too, might help.也尝试看看这里(SO) ,可能会有所帮助。
在声明性的情况下,我通过简单地导入“无法找到”的类来解决这个问题。
This exception was caused because that there is no record of parent table in MetaData instance, and this table needs to be retrieved in the DB.这个异常是因为MetaData实例中没有父表的记录,需要在DB中检索该表。 Invoke the function "reflect" of class MetaData to obtain all existed tables on the DB.
调用MetaData类的“reflect”函数来获取 DB 上所有存在的表。 It should be used like this
它应该像这样使用
def upgrade(migrate_engine):
meta.bind = migrate_engine
meta.reflect() # <------ Obtain all tables here.
aggregate_metadata.create()
aggregate_hosts.create()
A table is in a different file from another table that has a foreign key associate with it.一个表与另一个有外键关联的表位于不同的文件中。 In this case, sqlalchemy will fail to find the corresponding table when create tables, as shown below:
在这种情况下, sqlalchemy在创建表时会找不到对应的表,如下图:
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'
sqlalchemy.exc.NoReferencedTableError:与列“aggregate_metadata.aggregate_id”关联的外键找不到表“聚合”,用于生成目标列“id”的外键
For example:例如:
# 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()
Let's locate at the point that throw the exception让我们定位在抛出异常的点
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'
We could find the corresponding code and debug it:我们可以找到相应的代码并进行调试:
# 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 )
Then we could get below exceptions:然后我们可以得到以下异常:
Exception: imgrass->
- parenttable: aggregate_metadata
- parenttable.metadata: MetaData(bind=Engine(mysql+pymysql://imgrass:***@172.17.0.1/demo))
- tablekey: aggregates
- colname: id
So, the parenttable.metadata is an instance of class MetaData , and the tablekey is a table name.因此, parenttable.metadata是类MetaData的实例, tablekey是表名。 We could reasonably guess that the table aggregates should be included in the instance of class MetaData .
我们可以合理地猜测表聚合应该包含在类MetaData的实例中。 Considering that the definition of this table is in another file, and the MetaData instance has the connection way of DB(bind=xxx), there should be a function in class MetaData to obtain all tables in the DB.
考虑到这张表的定义在另一个文件中,并且MetaData实例有DB(bind=xxx)的连接方式,所以MetaData类中应该有一个函数来获取DB中的所有表。
In MetaData, we could find this function在 MetaData 中,我们可以找到这个函数
# File: sqlalchemy/sql/schema.py
class MetaData(SchemaItem):
...
def reflect(...):
r"""Load all available table definitions from the database.
...
From its description, we could guess its function, let's apply it in my script:从它的描述中,我们可以猜测它的功能,让我们将它应用到我的脚本中:
# 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()
It's okay!没关系!
Although the top voted answer solves the issue, replacing strings with objects forces you to define tables in a specific order (which can be non-trivial for very large databases).尽管投票最多的答案解决了这个问题,但用对象替换字符串会迫使您以特定顺序定义表(这对于非常大的数据库来说可能很重要)。 From the SQLAlchemy docs :
从SQLAlchemy 文档:
The advantage to using a string is that the in-python linkage between [different tables] is resolved only when first needed, so that table objects can be easily spread across multiple modules and defined in any order.
使用字符串的好处是 [不同表] 之间的 in-python 链接仅在第一次需要时才被解析,因此表对象可以轻松地分布在多个模块中并以任何顺序定义。
You can continue to use strings by passing the schema to the ForeignKey
.您可以通过将架构传递给
ForeignKey
继续使用字符串。 For example, instead of doing:例如,不要这样做:
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')
One can do:一个可以做到:
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')
Import the actual classes like below: 导入如下的实际类:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
and to suppress SQLAlchemy warnings use the following line in the configuration: 并禁止SQLAlchemy警告使用配置中的以下行:
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config ['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
Apart from this where is the 'price_range' table? 除此之外,'price_range'表在哪里? Add price_range table before adding ForeignKey.
在添加ForeignKey之前添加price_range表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.