Reputation: 2087
I've reflecting a load of tables in an exiting mysql db. I want to express that any columns of a certain name in any table default to datetime.now(). However naively looping through the tables and columns and just setting default on those I find that have a certain name doesn't work, When doing session.add(); session.flush() I get the following error:
AttributeError: 'builtin_function_or_method' object has no attribute '__visit_name__'
This would seem to be tied up in the call to _set_parent (and the this self._init_items(*toinit)
at line 721 in sqlalchemy.schema.
Does anyone know if there's a way to do this without either going through all of my reflected tables and adding Column(..) lines every where all doing the same thing or resorting to really ugly hacks?
Upvotes: 1
Views: 2804
Reputation: 315
Five years later, you can use event listeners[1]. You can register a listener with a function to run:
def do_this_on_column_reflect(inspector, table, column_info):
column_name = column_info.get("name")
if column_name == "create_datetime":
column_info["default"] = datetime.now()
event.listen(Table, "column_reflect", do_this_on_column_reflect)
[1] http://docs.sqlalchemy.org/en/latest/core/events.html#sqlalchemy.events.DDLEvents.column_reflect [2] http://docs.sqlalchemy.org/en/latest/core/event.html#sqlalchemy.event.listen
Upvotes: 3
Reputation: 54882
Another option is to override the columns that need defaults while reflecting:
Table('some_table', metadata,
Column('create_time', DateTime, default=datetime.now),
autoload=True)
Unfortunately you currently can't reflect the datatype and set SQLAlchemy side default at the same time. One could argue though that the datatype is part of the interface definition and so the redundancy doesn't create a maintenance issue - if the columns datatype changes you most likely need to change the default value function too.
Upvotes: 6
Reputation: 2087
OK, I've fixed this and it's a moderately horrid hack, in that I've using an internal method. You need to do:
from sqlalchemy.schema import ColumnDefault
#....
ColumnDefault(callable)._set_parent(column)
This produces the required behaviour. Note that you can also pass ColumnDefault the kwarg for_update=True and you'll this will change the behaviour to change on UPDATE rather than insert.
I feel dirty :-(
Upvotes: 5