【问题标题】:SQLAlchemy automap data and override some columnsSQLAlchemy 自动映射数据并覆盖某些列
【发布时间】:2016-07-06 04:20:25
【问题描述】:

是否可以在 SQLAlchemy 中将现有的数据库表自动映射到类中但覆盖某些表的某些字段?

我正在腌制 MetaData 对象,因为它需要一些时间,它包含所有表,但是当我尝试覆盖某些对象时,它会引发 MetaData 对象未绑定到引擎或连接的异常.

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine, MetaData, Column, String, Integer
import os, pickle

class MetadataCache(object):
    def __init__(self, engine, schema):
        self.engine = engine
        self.schema = schema
        self.metadata = None

    @property
    def cache_name(self):
        final_name = '{0}.{1}.cache'.format(self.engine.url.database,
                                            self.schema)
        return final_name

    def get_or_create_metadata(self):

        if os.path.exists(self.cache_name):
            with open(self.cache_name, 'r') as cachefile:
                self.metadata = pickle.load(cachefile)
        else:
            self.metadata = MetaData()
            self.metadata.reflect(bind=self.engine, schema=self.schema)
            with open(self.cache_name, 'w') as cachefile:
                pickle.dump(self.metadata, cachefile)

        return self.metadata

engine = create_engine('...')
metadata = MetadataCache(engine, 'schemaname').get_or_create_metadata()
Base = automap_base(metadata=metadata)


class User(Base):
    __tablename__ = 'user'

    id = Column('id', Integer, primary_key=True)
    name = Column('name', String)

class Profile(Base):
    __tablename__ = 'profile'
    id = Column('id', Integer, primary_key=True)
    userid = Column('userid', ForeignKey('user.id'))

Base.prepare(reflect=True)

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    引发错误是因为 Base 拥有的元数据(您传递给 automap_base 构造函数)未绑定到引擎,也不应该绑定到引擎。这只是意味着您必须将绑定传递给Base.prepare

    此外,由于您是手动反映元数据,因此不应告诉 Base.prepare 这样做。

    将最后一行更改为:

    Base.prepare(engine)
    

    编辑:当然,我在考虑 Base.prepare 需要引擎进行反射,但由于您传递的是预反射 MetaData(),因此您可以使用:

    Base.prepare()
    

    编辑:

    在回复下面的评论时,请注意必须将extend_existing=True 传递给Table

    class User(Base):
        __tablename__ = 'user'
        __table_args__ = {'extend_existing': True}
    
        id = Column('id', Integer, primary_key=True)
        name = Column('name', String)
    

    【讨论】:

    • 问题,至少据我了解,是我们只想使用腌制的元数据,而引擎(最初用于创建元数据)不一定可用(可能是因为数据库是'不可用)。你能想出一种解决方法吗?
    • 其实我在想答案时搞混了,引擎不需要传递给Base.prepare,我会编辑答案。
    • 问题中的示例实际上并不是独立的,所以我在这里创建了一个独立的版本:gist.github.com/jcrudy/fb30f079dfcf29fc6e3bd97b037eee1a。当我运行它时(您建议对最后一行进行更改),我得到 sqlalchemy.exc.InvalidRequestError: Table 'user' is already defined for this MetaData instance。指定 'extend_existing=True' 以重新定义现有 Table 对象上的选项和列。其实错误发生在User类的定义处。
    • @jcrudy 你需要在__table_args__ 这样做,我再次编辑了我的答案。
    • 我认为这是缺失的部分!谢谢。
    猜你喜欢
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多