SQLAlchemyのautomap拡張を使用して既存のデータベースのORMを生成しようとしていますが、InvalidRequestError例外が発生しています(「インスタンスはリフレッシュできません。完全なプライマリキーです。 ")タイムスタンプと外部キーからなる複合プライマリキーを使用するテーブルに挿入しようとするたびに発生します。SQLAlchemy automapにORMを挿入するとInvalidRequestErrorが発生する
これは、次のトレースバックを与える実行from sqlalchemy import create_engine, func, select
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import text
from sqlalchemy.ext.automap import automap_base
db_schema_cmds = [
'''CREATE TABLE users
(
u_id INTEGER NOT NULL,
name TEXT NOT NULL,
CONSTRAINT Key1 PRIMARY KEY (u_id)
);''',
'''CREATE TABLE posts
(
timestamp TEXT NOT NULL,
text TEXT NOT NULL,
u_id INTEGER NOT NULL,
CONSTRAINT Key2 PRIMARY KEY (timestamp,u_id),
CONSTRAINT users_have_posts FOREIGN KEY (u_id) REFERENCES users (u_id) ON DELETE CASCADE
);''']
# Create a new in-memory SQLite DB and execute the schema SQL commands.
db_engine = create_engine('sqlite://')
with db_engine.connect() as db_conn:
for cmd in db_schema_cmds:
db_conn.execute(text(cmd))
# Use automap to reflect the DB schema and generate ORM classes.
Base = automap_base()
Base.prepare(db_engine, reflect=True)
# Create aliases for the table classes generated.
User = Base.classes.users
Post = Base.classes.posts
session_factory = sessionmaker()
session_factory.configure(bind=db_engine)
# Add a user and a post to the DB.
session = session_factory()
new_user = User(name="John")
session.add(new_user)
session.commit()
new_post = Post(users=new_user, text='this is a test', timestamp=func.now())
session.add(new_post)
session.commit()
# Verify that the insertion worked.
new_user_id = session.execute(select([User])).fetchone()['u_id']
new_post_fk_user_id = session.execute(select([Post])).fetchone()['u_id']
assert new_user_id == new_post_fk_user_id
session.close()
:ここ
は、問題を再現するいくつかの最小限のコード例です
Traceback (most recent call last):
File "reproduce_InvalidRequestError.py", line 67, in <module>
session.commit()
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 801, in commit
self.transaction.commit()
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 392, in commit
self._prepare_impl()
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 372, in _prepare_impl
self.session.flush()
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 2019, in flush
self._flush(objects)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 2137, in _flush
transaction.rollback(_capture_exception=True)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\util\langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\util\compat.py", line 186, in reraise
raise value
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 2107, in _flush
flush_context.finalize_flush_changes()
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 395, in finalize_flush_changes
self.session._register_newly_persistent(other)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\session.py", line 1510, in _register_newly_persistent
instance_key = mapper._identity_key_from_state(state)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\mapper.py", line 2417, in _identity_key_from_state
for col in self.primary_key
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\mapper.py", line 2417, in <listcomp>
for col in self.primary_key
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\attributes.py", line 578, in get
value = state._load_expired(state, passive)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\state.py", line 474, in _load_expired
self.manager.deferred_scalar_loader(self, toload)
File "C:\Python\Python35\lib\site-packages\sqlalchemy\orm\loading.py", line 647, in load_scalar_attributes
"contain a full primary key." % state_str(state))
sqlalchemy.exc.InvalidRequestError: Instance <posts at 0x45d45f8> cannot be refreshed - it's not persistent and does not contain a full primary key.
私はcreate_engine
コールにecho=True
パラメータを追加した場合、私はそれを見ています挿入のために次のSQLを生成します。このSQLは、SQLiteのDBブラウザで実行するとうまく動作します。
INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO sqlalchemy.engine.base.Engine SELECT users.u_id AS users_u_id, users.name AS users_name FROM users WHERE users.u_id = ?
INFO sqlalchemy.engine.base.Engine (1,)
INFO sqlalchemy.engine.base.Engine INSERT INTO posts (timestamp, text, u_id) VALUES (CURRENT_TIMESTAMP, ?, ?)
INFO sqlalchemy.engine.base.Engine ('this is a test', 1)
INFO sqlalchemy.engine.base.Engine ROLLBACK
私もPost()
からusers
パラメータを削除しようとしたし、代わりにsession.add(new_post)
を呼び出す前に、ラインnew_user.posts_collection.append(new_post)
を追加し、それが生成され、同じSQLをもたらし、同じエラーが発生しました。
コンポジットキーを新しい整数型PK列に置き換えると、すべて正常に動作します。 (ない理想的なソリューションしかし、私はautomap
を使用している理由としては、DBのスキーマことを修正する必要がないことが好ましいですので、 DBを既存のを反映するためである。)私は、同様の質問、SQLAlchemy InvalidRequestError when using composite foreign keysを見つけ
、しかし、テーブルORMクラスでの継承の使用に関連していたようで、ORMテーブルクラスを定義するためには、DBを反映させるのではなく、ORMテーブルクラスを定義する必要がありました。
編集:私はもともと、この問題は複合主キーに外部キーが含まれているという事実に関連していると想定していました。受け入れられた答えは、外部キーが実際に問題の原因となっていないことを示しています。
は完璧[MCVE](HTTP提供いただき、ありがとうございます
timestamp
を提供://をstackoverflow.com/help/mcve)! –