Re: [sqlalchemy] Injecting User info into _history table to track who performed the change

2021-03-24 Thread JPLaverdure
Yup, makes perfect sense.

So what the code/fix is achieving, in effect, is what is described here:
https://docs.sqlalchemy.org/en/13/faq/ormconfiguration.html#i-m-getting-a-warning-or-error-about-implicitly-combining-column-x-under-attribute-y
Just using a different approach because of the inheritance. 

Cheers,

JP
On Wednesday, March 24, 2021 at 3:49:12 p.m. UTC-4 Simon King wrote:

> I'm not 100% confident here (the history_meta code does some pretty
> complicated stuff to deal with inheritance), but I'll give it a go:
>
> 1. You've adapted history_meta to add an extra column to history
> tables, called "accountable".
> 2. You've got an inheritance hierarchy (CompoundAdministration
> inherits from Process)
> 3. Both CompoundAdministration and Process use the Versioned mixin
> 4. This results in 2 new mapped classes, ProcessHistory and
> CompoundAdministrationHistory.
> 5. CompoundAdministrationHistory inherits from ProcessHistory
>
> Step 5 is the problem: CompoundAdministrationHistory inherits from
> ProcessHistory, but both tables have an "accountable" column. Normally
> that's a problem - when you set the
> CompoundAdministrationHistory.accountable attribute, should SQLAlchemy
> update the column in the compound_administration_history table, or
> process_history, or both? SQLAlchemy defaults to updating both, but
> warns you about the ambiguity.
>
> In this case, you really do want that property to target both columns,
> so your fix is correct:
>
> properties["accountable"] = (table.c.accountable,) + tuple(
> super_history_mapper.attrs.accountable.columns
> )
>
> This says that the "accountable" property should target the column on
> the local (inheriting) table as well as whatever columns the parent
> class was targeting.
>
> You should test that when you modify a CompoundAdministration object,
> you get a new row in both the compound_administration_history and the
> process_history tables, and that the "accountable" column is set
> correctly.
>
> I hope that makes sense,
>
> Simon
>
> On Wed, Mar 24, 2021 at 2:25 PM JPLaverdure  wrote:
> >
> > Hi Simon,
> >
> > Thanks for pointing out the collision, it kinda flew under the radar !
> > I renamed the column from "user" to "accountable" and but still got
> >
> > SAWarning:
> > Implicitly combining column process_history.accountable with column 
> compound_administration_history.accountable under attribute 'accountable'.
> > Please configure one or more attributes for these same-named columns 
> explicitly.
> >
> > As mentioned, these tables both also have a "changed" attribute, but did 
> not throw the warnings...
> > Looking a bit further, I spotted this piece of code in history_meta:
> > properties["changed"] = (table.c.changed,) + tuple(
> > super_history_mapper.attrs.changed.columns
> > )
> > So I added:
> > properties["accountable"] = (table.c.accountable,) + tuple(
> > super_history_mapper.attrs.accountable.columns
> > )
> >
> > And the warnings have disappeared.
> >
> > Could you explain what these instructions actually do ?
> >
> > Thanks
> > On Wednesday, March 24, 2021 at 5:18:02 a.m. UTC-4 Simon King wrote:
> >>
> >> I think the warning message is slightly misleading, probably because
> >> of the inheritance, but the fundamental problem is likely that your
> >> "process" table already has a "user" column, and you're trying to add
> >> a second "user" column in the process_history table, which can't work.
> >>
> >> If you use a different column name to store the user in the history
> >> table, does the warning go away?
> >>
> >> Simon
> >>
> >> On Tue, Mar 23, 2021 at 7:17 PM JPLaverdure  
> wrote:
> >> >
> >> > 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 

Re: [sqlalchemy] Injecting User info into _history table to track who performed the change

2021-03-24 Thread Simon King
I'm not 100% confident here (the history_meta code does some pretty
complicated stuff to deal with inheritance), but I'll give it a go:

1. You've adapted history_meta to add an extra column to history
tables, called "accountable".
2. You've got an inheritance hierarchy (CompoundAdministration
inherits from Process)
3. Both CompoundAdministration and Process use the Versioned mixin
4. This results in 2 new mapped classes, ProcessHistory and
CompoundAdministrationHistory.
5. CompoundAdministrationHistory inherits from ProcessHistory

Step 5 is the problem: CompoundAdministrationHistory inherits from
ProcessHistory, but both tables have an "accountable" column. Normally
that's a problem - when you set the
CompoundAdministrationHistory.accountable attribute, should SQLAlchemy
update the column in the compound_administration_history table, or
process_history, or both? SQLAlchemy defaults to updating both, but
warns you about the ambiguity.

In this case, you really do want that property to target both columns,
so your fix is correct:

properties["accountable"] = (table.c.accountable,) + tuple(
super_history_mapper.attrs.accountable.columns
)

This says that the "accountable" property should target the column on
the local (inheriting) table as well as whatever columns the parent
class was targeting.

You should test that when you modify a CompoundAdministration object,
you get a new row in both the compound_administration_history and the
process_history tables, and that the "accountable" column is set
correctly.

I hope that makes sense,

Simon

On Wed, Mar 24, 2021 at 2:25 PM JPLaverdure  wrote:
>
> Hi Simon,
>
> Thanks for pointing out the collision, it kinda flew under the radar !
> I renamed the column from "user" to "accountable" and but still got
>
> SAWarning:
> Implicitly combining column process_history.accountable with column 
> compound_administration_history.accountable under attribute 'accountable'.
> Please configure one or more attributes for these same-named columns 
> explicitly.
>
> As mentioned, these tables both also have a "changed" attribute, but did not 
> throw the warnings...
> Looking a bit further, I spotted this piece of code in history_meta:
> properties["changed"] = (table.c.changed,) + tuple(
> super_history_mapper.attrs.changed.columns
> )
> So I added:
> properties["accountable"] = (table.c.accountable,) + tuple(
> super_history_mapper.attrs.accountable.columns
> )
>
> And the warnings have disappeared.
>
> Could you explain what these instructions actually do ?
>
> Thanks
> On Wednesday, March 24, 2021 at 5:18:02 a.m. UTC-4 Simon King wrote:
>>
>> I think the warning message is slightly misleading, probably because
>> of the inheritance, but the fundamental problem is likely that your
>> "process" table already has a "user" column, and you're trying to add
>> a second "user" column in the process_history table, which can't work.
>>
>> If you use a different column name to store the user in the history
>> table, does the warning go away?
>>
>> Simon
>>
>> On Tue, Mar 23, 2021 at 7:17 PM JPLaverdure  wrote:
>> >
>> > 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 = 

Re: [sqlalchemy] Injecting User info into _history table to track who performed the change

2021-03-24 Thread JPLaverdure
Hi Simon,

Thanks for pointing out the collision, it kinda flew under the radar !
I renamed the column from "user" to "accountable" and but still got 

SAWarning: 
Implicitly combining column process_history.accountable with column 
compound_administration_history.accountable under attribute 'accountable'.  
Please configure one or more attributes for these same-named columns 
explicitly.

As mentioned, these tables both also have a "changed" attribute, but did 
not throw the warnings...
Looking a bit further, I spotted this piece of code in history_meta:
properties["changed"] = (table.c.changed,) + tuple(
super_history_mapper.attrs.changed.columns
)
So I added:
properties["accountable"] = (table.c.accountable,) + tuple(
super_history_mapper.attrs.accountable.columns
)

And the warnings have disappeared.

Could you explain what these instructions actually do ?

Thanks
On Wednesday, March 24, 2021 at 5:18:02 a.m. UTC-4 Simon King wrote:

> I think the warning message is slightly misleading, probably because
> of the inheritance, but the fundamental problem is likely that your
> "process" table already has a "user" column, and you're trying to add
> a second "user" column in the process_history table, which can't work.
>
> If you use a different column name to store the user in the history
> table, does the warning go away?
>
> Simon
>
> On Tue, Mar 23, 2021 at 7:17 PM JPLaverdure  wrote:
> >
> > 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
> >> > 

Re: [sqlalchemy] AttributeError: Neither 'QueryableAttribute' object nor 'Comparator' object has an attribute '__visit_name__'

2021-03-24 Thread Mike Bayer
hi - 

that's a bug!The .params() method is kind of forgotten. 
https://github.com/sqlalchemy/sqlalchemy/issues/6124 is added, however this is 
not a regression since this is using new functionality on select().   I think I 
have a fairly straightforward fix for this however it won't be in SQLAlchemy 
1.4.3, which needs to go out very soon.

For now I would advise sending the params directly to the session.execute() 
method.

On Tue, Mar 23, 2021, at 9:35 PM, Dane K Barney wrote:
> 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
>  
> .

-- 
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/c79f4dc5-19fe-45db-a32e-822023466e54%40www.fastmail.com.


Re: [sqlalchemy] Injecting User info into _history table to track who performed the change

2021-03-24 Thread JPLaverdure
Sure !  Here's an example.
This is the base 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'))

an one of the child classes:

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)


I have many types of processes that derive from the parent class and all of 
these throws a warning linked to the "user" Column Added in their 
respective _history.
For reference I implemented versioning using this recipe:
https://docs.sqlalchemy.org/en/13/_modules/examples/versioned_history/history_meta.html

I added my "user" column definition right under the "changed" column in 
history_meta.py.
The "changed" column does not trigger the warnings but my newly added 
"user" column does. 
So I'm guessing there is a extra step I forgot to add in the 
history_meta.py file but I cannot find what or where..

Thanks !
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 the history_meta.py example 
> from SQLAlchemy
> >>> > 
> 

Re: [sqlalchemy] Injecting User info into _history table to track who performed the change

2021-03-24 Thread Simon King
I think the warning message is slightly misleading, probably because
of the inheritance, but the fundamental problem is likely that your
"process" table already has a "user" column, and you're trying to add
a second "user" column in the process_history table, which can't work.

If you use a different column name to store the user in the history
table, does the warning go away?

Simon

On Tue, Mar 23, 2021 at 7:17 PM JPLaverdure  wrote:
>
> 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:
>>