简体   繁体   English

SQLAlchemy:根据属性将类映射到不同的表

[英]Sqlalchemy: Mapping a class to different tables depending on attribute

I'm trying to write to an existing database consisting of multiple tables of the following form 我正在尝试写入包含以下形式的多个表的现有数据库

total_usage_<application>:
    id
    version
    date

where <application> runs over a number of strings, say "appl1", "appl2" etc. Now I would like to use SQLAlchemy to create a single class like 其中<application>在许多字符串上运行,例如“ appl1”,“ appl2”等。现在,我想使用SQLAlchemy创建单个类,例如

class DBEntry:
    id = ''
    application = ''
    version = ''
    date = ''

such that an instance foo of DBEntry gets mapped to the table "total_usage_" + foo.application . 这样DBEntry的实例foo被映射到表"total_usage_" + foo.application How can this be achieved? 如何做到这一点?

OK, please take a look at example below, which is self-contained and might show you one way this can be done. 好的,请看下面的示例,它是独立的,可能会向您显示一种完成此操作的方法。 It assumes that you know the app_name when you start your program, as well as it assumes that table names follow some naming convention, which obviously you can adapt to your needs or have it completely manually configured by overriding __tablename__ in each mapped class. 它假定您在启动程序时就知道app_name ,并且假定表名遵循某种命名约定,显然,您可以适应您的需要,或者通过在每个映射的类中重写__tablename__来完全手动配置它。
But the main idea is that the configuration is wrapped into a function (which can be done also using module import with pre-defined constant beforehand). 但是主要思想是将配置包装到一个函数中(也可以使用预先带有预定义常量的模块导入来完成)。

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, scoped_session, sessionmaker

def camel_to_under(name):
    import re
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

def configure_database(app_name):
    """ @return: dictionary with all the classes mapped to proper tables for
    specific application.  """
    from sqlalchemy.ext.declarative import declared_attr
    from sqlalchemy.ext.declarative import declarative_base

    class Base(object):
        # docs: http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#augmenting-the-base
        @declared_attr
        def __tablename__(cls):
            return camel_to_under(cls.__name__) + "_" + app_name

        def __repr__(self):
            attrs = class_mapper(self.__class__).column_attrs # only columns
            # attrs = class_mapper(self.__class__).attrs # show also relationships
            return u"{}({})".format(self.__class__.__name__,
                ', '.join('%s=%r' % (k.key, getattr(self, k.key))
                    for k in sorted(attrs)
                )
            )

    Base = declarative_base(cls=Base)

    class Class1(Base):
        id = Column(Integer, primary_key=True)
        name = Column(String)

    class Class1Child(Base):
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey(Class1.id))
        name = Column(String)
        # relationships
        parent = relationship(Class1, backref="children")

    # return locals()
    return {
        "app_name": app_name,
        "Base": Base,
        "Class1": Class1,
        "Class1Child": Class1Child,
        }

def _test():
    """ Little test for the app.  """
    engine = create_engine(u'sqlite:///:memory:', echo=True)
    session = scoped_session(sessionmaker(bind=engine))

    app_name = "app1"
    x = configure_database(app_name)

    # assign real names
    app_name = x["app_name"]
    Base = x["Base"]
    Class1 = x["Class1"]
    Class1Child = x["Class1Child"]

    # create DB model (not required in production)
    Base.metadata.create_all(engine)

    # test data
    cc = Class1Child(name="child-11")
    c1 = Class1(name="some instance", children=[cc])
    session.add(c1)
    session.commit()

_test()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM