Python 2.7 使用带列重写的元类的SQLAlchemy反射

Python 2.7 使用带列重写的元类的SQLAlchemy反射,python-2.7,reflection,sqlalchemy,flask-sqlalchemy,geoalchemy,Python 2.7,Reflection,Sqlalchemy,Flask Sqlalchemy,Geoalchemy,我有一组动态数据库表(带有PostGIS的Postgres 9.3),我正在使用python元类映射这些表: cls = type(str(tablename), (db.Model,), {'__tablename__':tablename}) 其中,db.Model是通过flask sqlalchemy生成的db对象,tablename有点unicode。 然后将cls添加到应用程序范围的字典current\u app.class\u references(使用Flask的current\

我有一组动态数据库表(带有PostGIS的Postgres 9.3),我正在使用python元类映射这些表:

cls = type(str(tablename), (db.Model,), {'__tablename__':tablename})
其中,db.Model是通过flask sqlalchemy生成的db对象,tablename有点unicode。 然后将cls添加到应用程序范围的字典
current\u app.class\u references
(使用Flask的current\u app)中,以避免多次尝试实例化该类

每个表都包含一个几何列,
wkb_geometry
以众所周知的二进制格式存储。我想将这些映射用于检索GeoJSON的最终目标

如果我事先声明表,我会使用:

class GeoPoly():
    __tablename__ = 'somename'
    wkb_geometry = db.Column(Geometry("POLYGON"))
    #more columns...
由于我试图动态地执行此操作,因此需要能够用已知类型覆盖
cls1
的反射

尝试:
  • 使用反射覆盖语法显式定义列

    cls = type(str(tablename), (db.Model,), {'__tablename__':tablename,
        'wkb_geometry':db.Column(Geometry("POLYGON"))})
    
  • 在重新启动时返回以下内容,即类尚未实例化: InvalidRequestError:已为此元数据实例定义了表“tablename”。指定“extend_existing=True”以重新定义现有表对象上的选项和列

  • 将mixin与上面定义的类一起使用(sanstablename):

  • 再次强调元数据问题

  • 在实例化类后重写列定义属性:

    cls = type(str(tablename), (db.Model,), {'__tablename__':tablename})
    current_app.class_references[tablename] = cls
    cls.wkb_geometry = db.Column(Geometry("POLYGON"))
    
  • 其结果是:

    InvalidRequestError:将column tablename.wkb_几何图形与column tablename.wkb_几何图形隐式组合在属性“wkb_几何图形”下。请为这些同名列显式配置一个或多个属性


    是否可以使用元数据构造来支持动态反射**和**覆盖所有表上都可用的已知列?

    我不确定是否完全遵循了您的操作,但是我过去在继承自
    DeclarativeMeta
    的自定义元类上,在我自己的
    \uuuu init\uuuu
    方法中重写了反射列。每当使用新基类时,它都会检查“wkb_geometry”列名,并将其替换为您创建的列名(副本)

    import sqlalchemy as sa
    from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base
    
    wkb_geometry = db.Column(Geometry("POLYGON"))
    
    class MyMeta(DeclarativeMeta):
        def __init__(cls, clsname, parents, dct):
            for key, val in dct.iteritems():
                if isinstance(sa.Column) and key is 'wkb_geometry':
                    dct[key] = wkb_geometry.copy()
    
    MyBase = declarative_base(metaclass=MyMeta)
    
    cls = type(str(tablename), (MyBase,), {'__tablename__':tablename})
    

    这可能不适合你,但这是一个想法。例如,您可能需要将
    db.Model
    添加到
    MyBase
    元组中。

    这就是我在依赖
    自动加载
    进行其他操作时用于自定义特定列的功能。下面的代码假定名为
    my_table
    的表的现有声明性
    Base
    对象。它加载所有列的元数据,但覆盖名为
    polygon
    的列的定义:

    class MyTable(Base):
        __tablename__ = 'my_table'
        __table_args__ = (Column(name='polygon', type=Geometry("POLYGON"),
                          {'autoload':True})
    
    字典中可以提供构造函数的其他参数。请注意,词典必须在列表中最后出现

    SQLAlchemy文档提供了更多细节和示例

    class MyTable(Base):
        __tablename__ = 'my_table'
        __table_args__ = (Column(name='polygon', type=Geometry("POLYGON"),
                          {'autoload':True})