SQLAlchemy:从表名中获取模型。这可能意味着尽可能将一些函数附加到元类构造函数

2024-05-19 07:43:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个函数,在给定表名的情况下,返回具有table name的模型。 例如:

class Model(Base):
    __tablename__ = 'table'
    ...a bunch of Columns

def getModelFromTableName(tablename):
   ...something magical

所以getModelFromTableName('table')应该返回模型类。

我的目标是在我制作的一个简单表单生成器中使用该函数,因为FormAlchemy不适用于python3.2,我希望它能够很好地处理外键。

有谁能给我一些关于如何让getModelFromTableName工作的建议吗?

我有一个想法(这可能是完全错误的,我以前从未使用过元类…)

如果我让我的模型类继承自基类以及其他类(TableReg),并且在一些全局字典或单例中有TableReg store Model.tablename的类meta,该怎么办。

我意识到这可能是完全不可能的,因为Base的元类做了一些我不想破坏的非常重要和非常漂亮的事情,但我认为必须有一种方法让我在模型的元类中附加一点构造函数代码。或者我不明白。


Tags: columnsof函数name模型basemodeldef
3条回答

注意OrangeTux答案不考虑模式。如果在不同模式中有表同音词,请使用:

def get_class_by_tablename(table_fullname):
  """Return class reference mapped to table.

  :param table_fullname: String with fullname of table.
  :return: Class reference or None.
  """
  for c in Base._decl_class_registry.values():
    if hasattr(c, '__table__') and c.__table__.fullname == table_fullname:
      return c

fullname是一个表属性,请参见:

github.com/sqlalchemy/sqlalchemy/blob/master/lib/sqlalchemy/sql/schema.py#L530-L532

此函数的实用函数已添加到SQLAlchemy-Utils。有关详细信息,请参见get_class_by_table docs。SQLAlchemy Utils中的解决方案也能够覆盖单表继承场景。

import sqlalchemy as sa


def get_class_by_table(base, table, data=None):
    """
    Return declarative class associated with given table. If no class is found
    this function returns `None`. If multiple classes were found (polymorphic
    cases) additional `data` parameter can be given to hint which class
    to return.

    ::

        class User(Base):
            __tablename__ = 'entity'
            id = sa.Column(sa.Integer, primary_key=True)
            name = sa.Column(sa.String)


        get_class_by_table(Base, User.__table__)  # User class


    This function also supports models using single table inheritance.
    Additional data paratemer should be provided in these case.

    ::

        class Entity(Base):
            __tablename__ = 'entity'
            id = sa.Column(sa.Integer, primary_key=True)
            name = sa.Column(sa.String)
            type = sa.Column(sa.String)
            __mapper_args__ = {
                'polymorphic_on': type,
                'polymorphic_identity': 'entity'
            }

        class User(Entity):
            __mapper_args__ = {
                'polymorphic_identity': 'user'
            }


        # Entity class
        get_class_by_table(Base, Entity.__table__, {'type': 'entity'})

        # User class
        get_class_by_table(Base, Entity.__table__, {'type': 'user'})


    :param base: Declarative model base
    :param table: SQLAlchemy Table object
    :param data: Data row to determine the class in polymorphic scenarios
    :return: Declarative class or None.
    """
    found_classes = set(
        c for c in base._decl_class_registry.values()
        if hasattr(c, '__table__') and c.__table__ is table
    )
    if len(found_classes) > 1:
        if not data:
            raise ValueError(
                "Multiple declarative classes found for table '{0}'. "
                "Please provide data parameter for this function to be able "
                "to determine polymorphic scenarios.".format(
                    table.name
                )
            )
        else:
            for cls in found_classes:
                mapper = sa.inspect(cls)
                polymorphic_on = mapper.polymorphic_on.name
                if polymorphic_on in data:
                    if data[polymorphic_on] == mapper.polymorphic_identity:
                        return cls
            raise ValueError(
                "Multiple declarative classes found for table '{0}'. Given "
                "data row does not match any polymorphic identity of the "
                "found classes.".format(
                    table.name
                )
            )
    elif found_classes:
        return found_classes.pop()
    return None

灵感来自Eevee的评论:

def get_class_by_tablename(tablename):
  """Return class reference mapped to table.

  :param tablename: String with name of table.
  :return: Class reference or None.
  """
  for c in Base._decl_class_registry.values():
    if hasattr(c, '__tablename__') and c.__tablename__ == tablename:
      return c

相关问题 更多 >

    热门问题