[sqlalchemy] AttributeError: Neither 'QueryableAttribute' object nor 'Comparator' object has an attribute '__visit_name__'
I am using SQLAlchemy 1.4.2 and have been encountering this strange error message which I've managed to boil down to this minimal example: import sqlalchemy as sa from sqlalchemy.orm import declarative_base, relationship Base = declarative_base() class Parent(Base): __tablename__ = "parent" id = sa.Column(sa.Integer, primary_key=True) class Child(Base): __tablename__ = "child" id = sa.Column(sa.Integer, primary_key=True) parent_id = sa.Column(sa.Integer, sa.ForeignKey("parent.id")) parent = relationship("Parent") statement = sa.select([Child.id]).join(Child.parent).where(Parent.id == sa.bindparam("id")) statement = statement.params(id=10) The call to statement.params(...) is throwing the following stacktrace. Can anyone tell me what I'm doing wrong? Traceback (most recent call last): File "test_sqlalchemy_error.py", line 20, in statement = statement.params(id=10) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 346, in params return self._replace_params(False, optionaldict, kwargs) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 363, in _replace_params return cloned_traverse(self, {}, {"bindparam": visit_bindparam}) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 742, in cloned_traverse obj = clone(obj, deferred_copy_internals=deferred_copy_internals) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 735, in clone newelem._copy_internals(clone=clone, **kw) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/selectable.py", line 5208, in _copy_internals clone=clone, omit_attrs=("_from_obj",), **kw File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/traversals.py", line 718, in _copy_internals result = meth(attrname, self, obj, **kw) File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/traversals.py", line 777, in visit_setup_join_tuple for (target, onclause, from_, flags) in element File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/traversals.py", line 777, in for (target, onclause, from_, flags) in element File ".venv/lib/python3.7/site-packages/sqlalchemy/sql/visitors.py", line 736, in clone meth = visitors.get(newelem.__visit_name__, None) File ".venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 308, in __getattr__ replace_context=err, File ".venv/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 198, in raise_ raise exception AttributeError: Neither 'QueryableAttribute' object nor 'Comparator' object associated with Child.parent has an attribute '__visit_name__' -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/e1696eff-495e-4db9-a88a-cc385bbc8690n%40googlegroups.com.
Re: [sqlalchemy] Injecting User info into _history table to track who performed the change
It seems I lost my previous email.. Here it is again: Sure ! Here are 2 classes for which the generated _history sister tables (generated by history_meta.py) throw the warnings: *The Parent class:* class Process(Versioned, Base, UtilityMixin): __tablename__ = 'process' __table_args__ = {} id = Column(Integer, primary_key=True) discriminator = Column('type', String(64)) timestamp = Column(DateTime, nullable=False) start_date = Column(Date, nullable=False) am_pm = Column(String(8)) probable_end_date = Column(Date) end_date = Column(Date) user = Column(String(128), nullable=False) comments = Column(Text) __mapper_args__ = {'polymorphic_on': discriminator, 'polymorphic_identity': 'process', 'order_by': [start_date.desc(), id.desc()]} protocol_id = Column(Integer, ForeignKey('protocol.id', onupdate='cascade', ondelete='restrict')) process_type_id = Column(Integer, ForeignKey('process_type.id', onupdate='cascade', ondelete='restrict')) protocol = relationship(Protocol, backref='processes', uselist=False) process_type = relationship(ProcessType, backref='processes', uselist=False) *The Child class:* class CompoundAdministration(Process): __tablename__ = 'compound_administration' __table_args__ = {} __mapper_args__ = {'polymorphic_identity': 'compound_admin'} id = Column(Integer, ForeignKey('process.id', onupdate='cascade', ondelete='cascade'), primary_key=True) dose = Column(String(64)) substance = Column(String(128)) frequency = Column(String(64)) duration = Column(String(64)) route_id = Column(Integer, ForeignKey('administration_route.id', onupdate='cascade', ondelete='restrict')) route = relationship(AdministrationRoute, uselist=False) As reminder, versioning was implemented using this recipe/example from SQLA: https://docs.sqlalchemy.org/en/13/_modules/examples/versioned_history/history_meta.html And here is the associated warning: SAWarning: Implicitly combining column process_history.user with column compound_administration_history.user under attribute 'user'. Please configure one or more attributes for these same-named columns explicitly. Thanks for your help resolving this, JP On Tuesday, March 23, 2021 at 6:24:03 a.m. UTC-4 Simon King wrote: > Can you show us the mapping definitions that are triggering these warnings? > > On Mon, Mar 22, 2021 at 6:29 PM JPLaverdure wrote: > > > > Hi, > > > > Thanks for your support guys. > > > > I've implemented logging the user's email in the _history tables by > adding this Column definition inside my history_meta.py file: > > cols.append( > > Column( > > "user", > > String, > > info=version_meta, > > ) > > ) > > but i'm running into a good load of SAWarnings stating that there is an > implicit combining of the "user" column taking place > > (I have multi-table inheritance setup for some entities, those are the > ones throwing the warning) > > I don't get why the column "changed" (which holds the timestamp of the > change) and is defined in exactly the same way does not generate these > warnings ? > > What configuration setting am I missing here ? > > > > I found this > > > https://docs.sqlalchemy.org/en/13/faq/ormconfiguration.html#i-m-getting-a-warning-or-error-about-implicitly-combining-column-x-under-attribute-y > > But it doesn't seem to fit 100% with what I'm seeing inside > history_meta.py > > > > Thanks !! > > On Monday, March 15, 2021 at 4:33:40 p.m. UTC-4 Jonathan Vanasco wrote: > >> > >> Going beyond what Simon did.. > >> > >> I typically make make a table like `user_transaction`, which has all of > the relevant information for the transaction: > >> > >> * User ID > >> * Timestamp > >> * Remote IP > >> > >> Using the sqlalchemy hooks, I'll then do something like: > >> > >> * update the object table with the user_transaction id > >> or > >> * use an association table that tracks a user_transaction_id to an > object id and version > >> > >> FYI, Simon -- as of a few weeks ago, that pattern is now part of the > pyramid sqlalchemy starter template! > >> > >> On Monday, March 15, 2021 at 6:46:02 AM UTC-4 Simon King wrote: > >>> > >>> I use pyramid as a web framework, and when I create the DB session for > >>> each request, I add a reference to the current request object to the > >>> DB session. The session object has an "info" attribute which is > >>> intended for application-specific things like this: > >>> > >>> > https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.info > >>> > >>> Then, in the before_flush event handler, I retrieve the request object > >>> from session.info, and then I can add whatever request-specific info I > >>> want to the DB. > >>> > >>> Simon > >>> > >>> On Sun, Mar 14, 2021 at 4:05 PM JPLaverdure > wrote: > >>> > > >>> > Hi Elmer, > >>> > > >>> > Thanks for your reply ! > >>> > My issue is not with obtaining the info I want to inject (the logged > in users's email), I already have that all ready to go :) > >>> > > >>> > My whole database is versioned using
Re: [sqlalchemy] Injecting User info into _history table to track who performed the change
Can you show us the mapping definitions that are triggering these warnings? On Mon, Mar 22, 2021 at 6:29 PM JPLaverdure wrote: > > Hi, > > Thanks for your support guys. > > I've implemented logging the user's email in the _history tables by adding > this Column definition inside my history_meta.py file: > cols.append( > Column( > "user", > String, > info=version_meta, > ) > ) > but i'm running into a good load of SAWarnings stating that there is an > implicit combining of the "user" column taking place > (I have multi-table inheritance setup for some entities, those are the ones > throwing the warning) > I don't get why the column "changed" (which holds the timestamp of the > change) and is defined in exactly the same way does not generate these > warnings ? > What configuration setting am I missing here ? > > I found this > https://docs.sqlalchemy.org/en/13/faq/ormconfiguration.html#i-m-getting-a-warning-or-error-about-implicitly-combining-column-x-under-attribute-y > But it doesn't seem to fit 100% with what I'm seeing inside history_meta.py > > Thanks !! > On Monday, March 15, 2021 at 4:33:40 p.m. UTC-4 Jonathan Vanasco wrote: >> >> Going beyond what Simon did.. >> >> I typically make make a table like `user_transaction`, which has all of the >> relevant information for the transaction: >> >> * User ID >> * Timestamp >> * Remote IP >> >> Using the sqlalchemy hooks, I'll then do something like: >> >> * update the object table with the user_transaction id >> or >> * use an association table that tracks a user_transaction_id to an object id >> and version >> >> FYI, Simon -- as of a few weeks ago, that pattern is now part of the pyramid >> sqlalchemy starter template! >> >> On Monday, March 15, 2021 at 6:46:02 AM UTC-4 Simon King wrote: >>> >>> I use pyramid as a web framework, and when I create the DB session for >>> each request, I add a reference to the current request object to the >>> DB session. The session object has an "info" attribute which is >>> intended for application-specific things like this: >>> >>> https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.info >>> >>> Then, in the before_flush event handler, I retrieve the request object >>> from session.info, and then I can add whatever request-specific info I >>> want to the DB. >>> >>> Simon >>> >>> On Sun, Mar 14, 2021 at 4:05 PM JPLaverdure wrote: >>> > >>> > Hi Elmer, >>> > >>> > Thanks for your reply ! >>> > My issue is not with obtaining the info I want to inject (the logged in >>> > users's email), I already have that all ready to go :) >>> > >>> > My whole database is versioned using the history_meta.py example from >>> > SQLAlchemy >>> > https://docs.sqlalchemy.org/en/13/_modules/examples/versioned_history/history_meta.html >>> > >>> > I was hoping for a simple way to inject the user info into the _history >>> > row creation steps. >>> > >>> > The SQLAlchemy example makes use of this event listener: >>> > >>> > def versioned_session(session): >>> > >>> > @event.listens_for(session, "before_flush") >>> > def before_flush(session, flush_context, instances): >>> > for obj in versioned_objects(session.dirty): >>> > create_version(obj, session) >>> > for obj in versioned_objects(session.deleted): >>> > create_version(obj, session, deleted=True) >>> > >>> > So I'm tempted to follow the same strategy and just override this >>> > listener to supplement it with the user info but I'm wondering how to >>> > pass in non SQLAlchemy info into its execution context... >>> > >>> > So basically, I have the info I want to inject, I'm just not sure how to >>> > pass it to SQLAlchemy >>> > >>> > Thanks, >>> > >>> > JP >>> > >>> > On Friday, March 12, 2021 at 6:55:19 p.m. UTC-5 elmer@gmail.com wrote: >>> >> >>> >> Hi JP, >>> >> >>> >> Depending on how you've implemented your history tracking, that routine >>> >> is quite far removed from your web framework and getting a neat, clean >>> >> way of dealing with that might not be within reach. >>> >> >>> >> However, most web frameworks have some concept of a threadlocal request >>> >> (or function to retrieve it), which you could invoke and if such a >>> >> request exists, you could use that to load whatever user identity you >>> >> have available on there (again, the details differ, but this tends to be >>> >> a shared feature). From there you can store the user either as a foreign >>> >> key, or a unique identifier like email. Which one you pick would depend >>> >> on how you want the history to be affected when you delete a user record >>> >> for example. >>> >> >>> >> >>> >> >>> >> On Fri, Mar 12, 2021 at 11:58 PM JPLaverdure wrote: >>> >>> >>> >>> Hello everyone, >>> >>> >>> >>> We already have the ability to timestamp the creation of the history >>> >>> row, but it would also be interesting to be able to track the user >>> >>> responsible for the content update. >>> >>> I would like to get suggestions on the best way to