覆盖sqlalchemy反射表中的默认值

时间:2009-06-02 14:30:43

标签: python sqlalchemy

我在现有的mysql数据库中反映了一大堆表。我想表示任何表中某个名称的任何列都默认为datetime.now()。然而,天真地循环遍历表和列,只是在我发现具有某个名称的那些上设置默认值不起作用,在执行session.add()时; session.flush()我收到以下错误:

AttributeError: 'builtin_function_or_method' object has no attribute '__visit_name__'

这似乎与调用_set_parent(以及sqlalchemy.schema中第721行的self._init_items(*toinit))有关。

有没有人知道是否有办法做到这一点,既没有通过我所有的反射表,也没有添加Column(..)行,所有这些都做同样的事情或诉诸真正丑陋的黑客?

3 个答案:

答案 0 :(得分:6)

另一种选择是在反映时覆盖需要默认值的列:

Table('some_table', metadata,
    Column('create_time', DateTime, default=datetime.now),
    autoload=True)

不幸的是,您目前无法反映数据类型并同时设置SQLAlchemy端默认值。有人可能会争辩说,数据类型是接口定义的一部分,因此冗余不会产生维护问题 - 如果列数据类型发生更改,则您很可能也需要更改默认值函数。

答案 1 :(得分:5)

好的,我已经解决了这个问题,这是一个中等可怕的黑客,因为我使用的是内部方法。你需要这样做:

from sqlalchemy.schema import ColumnDefault
#....
ColumnDefault(callable)._set_parent(column)

这会产生所需的行为。请注意,您也可以传递ColumnDefault的kwarg for_update = True,这将改变行为以在UPDATE上更改而不是插入。

我觉得很脏: - (

答案 2 :(得分:3)

五年后,您可以使用事件监听器[1]。您可以使用要运行的函数注册侦听器:

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