SQLAlchemy中使用的反思与元类覆盖列(SQLAlchemy Reflection Using

2019-10-21 01:24发布

我有一组我使用一个Python元类的动态映射数据库表(Postgres的9.3在PostGIS)的:

cls = type(str(tablename), (db.Model,), {'__tablename__':tablename})

其中,db.Model是经由烧瓶-SQLAlchemy的和表名的分贝对象是一个位Unicode的。 CLS的然后被添加到应用宽字典current_app.class_references (使用瓶的CURRENT_APP),以避免企图类多次实例化。

每个表都包含一个几何列, wkb_geometry存储所熟知的二进制文件。 我要地图这些使用geoalchemy2与检索GeoJSON的最终目标。

如果我宣布表是先验的,我会用:

class GeoPoly():
    __tablename__ = 'somename'
    wkb_geometry = db.Column(Geometry("POLYGON"))
    #more columns...

因为我想要动态地做到这一点,我需要能够覆盖的反射cls1与已知的类型。

尝试:

  1. 定义列明确,使用反射覆盖语法。

     cls = type(str(tablename), (db.Model,), {'__tablename__':tablename, 'wkb_geometry':db.Column(Geometry("POLYGON"))}) 

返回上一个新的启动下,即类没有被实例化:InvalidRequestError:表“表名”已是该元数据实例定义。 指定“extend_existing = TRUE”重新定义现有的表对象上的选项和列

  1. 使用混入有上述(SANS 表名 )中定义的类:

     cls = type(str(tablename), (GeoPoly, db.Model), {'__tablename__':tablename}) 

同样元数据的问题。

  1. 覆盖列定义属性的类实例化后:

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

这会导致:

InvalidRequestError:隐柱tablename.wkb_geometry与列tablename.wkb_geometry下属性“wkb_geometry”相结合。 请配置这些明确同名列一个或多个属性。

是否可以使用元数据结构支持动态反射**和*覆盖知将可在所有表列?

Answer 1:

我不知道我是否严格遵循你在做什么,但我重写反映了我自己的里面,在过去的列__init__在从继承的自定义元类方法DeclarativeMeta 。 使用新的基类中的任何时候,它检查“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.ModelMyBase元组,例如。



Answer 2:

这是我用它来定制特定的列,而在依靠autoload的一切。 下面的代码假定现有声明Base名为表对象my_table 。 它加载所有列的元数据,而是覆盖了一个名为列的定义polygon

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

其他参数Table可以在字典中提供的构造。 需要注意的是字典必须出现在列表的最后!

在SQLAlchemy的文档使用的混合方法与__table__提供了更多的细节和例子。



文章来源: SQLAlchemy Reflection Using Metaclass with Column Override