Closed
Description
Migrated issue, originally created by Jack Zhou (@univerio)
When using single table inheritance, eager_defaults
seems to be affected by the columns that the subclasses add to the base table:
class Foo(Base):
__tablename__ = "foo"
id = Column(Integer, primary_key=True)
type = Column(String)
created_at = Column(DateTime(), server_default=func.now())
__mapper_args__ = {
"polymorphic_on": type,
"polymorphic_identity": "foo",
"eager_defaults": True,
}
class Bar(Foo):
bar = Column(String)
__mapper_args__ = {
"polymorphic_identity": "bar",
}
foo = Foo()
session.add(foo)
session.flush()
This results in this exception
Traceback (most recent call last):
File "sqla.py", line 59, in <module>
main()
File "sqla.py", line 51, in main
session.flush()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2139, in flush
self._flush(objects)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2259, in _flush
transaction.rollback(_capture_exception=True)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
raise value
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2223, in _flush
flush_context.execute()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 389, in execute
rec.execute(self)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 548, in execute
uow
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 181, in save_obj
mapper, table, insert)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 856, in _emit_insert_statements
value_params)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 1043, in _postfetch
dict_[mapper._columntoproperty[col].key] = row[col]
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py", line 2991, in __missing__
(column, self.mapper))
sqlalchemy.orm.exc.UnmappedColumnError: No column foo.bar is configured on mapper Mapper|Foo|foo...
When attempting to add a Bar
instead,
bar = Bar()
session.add(bar)
session.flush()
A different exception is raised:
Traceback (most recent call last):
File "sqla.py", line 62, in <module>
main()
File "sqla.py", line 54, in main
session.commit()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 874, in commit
self.transaction.commit()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 461, in commit
self._prepare_impl()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 441, in _prepare_impl
self.session.flush()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2139, in flush
self._flush(objects)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2259, in _flush
transaction.rollback(_capture_exception=True)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
raise value
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2223, in _flush
flush_context.execute()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 389, in execute
rec.execute(self)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 548, in execute
uow
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 193, in save_obj
update_version_id in states_to_update
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 1008, in _finalize_insert_update_commands
only_load_props=toload_now)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 223, in load_on_ident
return q.one()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2749, in one
ret = self.one_or_none()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2719, in one_or_none
ret = list(self)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2786, in __iter__
context = self._compile_context()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 3320, in _compile_context
"No column-based properties specified for "
sqlalchemy.exc.InvalidRequestError: No column-based properties specified for refresh operation. Use session.expire() to reload collections and related items.
When I specify "with_polymorphic": "*"
on Foo
,
class Foo(Base):
__tablename__ = "foo"
id = Column(Integer, primary_key=True)
type = Column(String)
created_at = Column(DateTime(), server_default=func.now())
__mapper_args__ = {
"polymorphic_on": type,
"polymorphic_identity": "foo",
"eager_defaults": True,
"with_polymorphic": "*",
}
bar = Bar()
session.add(bar)
session.flush()
Yet another exception is raised:
Traceback (most recent call last):
File "sqla.py", line 63, in <module>
main()
File "sqla.py", line 55, in main
session.commit()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 874, in commit
self.transaction.commit()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 461, in commit
self._prepare_impl()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 441, in _prepare_impl
self.session.flush()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2139, in flush
self._flush(objects)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2259, in _flush
transaction.rollback(_capture_exception=True)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
raise value
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 2223, in _flush
flush_context.execute()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 389, in execute
rec.execute(self)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/unitofwork.py", line 548, in execute
uow
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 193, in save_obj
update_version_id in states_to_update
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/persistence.py", line 1008, in _finalize_insert_update_commands
only_load_props=toload_now)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 223, in load_on_ident
return q.one()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2749, in one
ret = self.one_or_none()
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 2719, in one_or_none
ret = list(self)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 90, in instances
util.raise_from_cause(err)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
raise value
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 57, in instances
for query_entity in query._entities
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 57, in <listcomp>
for query_entity in query._entities
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/query.py", line 3636, in row_processor
polymorphic_discriminator=self._polymorphic_discriminator
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 299, in _instance_processor
mapper._props[k] for k in only_load_props)
File "/home/jack/dev/test/.venv/lib/python3.5/site-packages/sqlalchemy/orm/loading.py", line 299, in <genexpr>
mapper._props[k] for k in only_load_props)
KeyError: 'bar'
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
sqlalchemy-bot commentedon Feb 9, 2017
Michael Bayer (@zzzeek) wrote:
hint: you're using postgresql, bugs are related to returning
sqlalchemy-bot commentedon Feb 9, 2017
Jack Zhou (@univerio) wrote:
This happens on SQLite as well:
Traceback:
sqlalchemy-bot commentedon Feb 9, 2017
Michael Bayer (@zzzeek) wrote:
note the eager_defaults is also doing a superfluous SELECT here and I've added #3909 for that.
sqlalchemy-bot commentedon Feb 9, 2017
Changes by Michael Bayer (@zzzeek):
sqlalchemy-bot commentedon Feb 9, 2017
Changes by Michael Bayer (@zzzeek):
sqlalchemy-bot commentedon Feb 9, 2017
Changes by Michael Bayer (@zzzeek):
sqlalchemy-bot commentedon Feb 9, 2017
Michael Bayer (@zzzeek) wrote:
yes SQLIte the "foo" cases work though
sqlalchemy-bot commentedon Feb 9, 2017
Michael Bayer (@zzzeek) wrote:
Check for columns not part of mapping, correct mapping for eager_defaults
Fixed two closely related bugs involving the mapper eager_defaults
flag in conjunction with single-table inheritance; one where the
eager defaults logic would inadvertently try to access a column
that's part of the mapper's "exclude_properties" list (used by
Declarative with single table inheritance) during the eager defaults
fetch, and the other where the full load of the row in order to
fetch the defaults would fail to use the correct inheriting mapper.
Fixes: #3908
Change-Id: Ie745174c917d512e2c46d9e3cc14512cde53cc9a
→ 540bcff
sqlalchemy-bot commentedon Feb 9, 2017
Changes by Michael Bayer (@zzzeek):