【问题标题】:How is lookup table data declared and initialized in SQLAlchemy?SQLAlchemy 中如何声明和初始化查找表数据?
【发布时间】:2017-06-05 07:02:57
【问题描述】:

动机

举一个简单的例子,其中一列数据需要用 SQL 中的枚举类型来表示:

+------------------------------------------+
| user                                     |
+----+------+-----+------------------------+
| id | name | age | relationship_status_id |
+----+------+-----+------------------------+
| 1  | John | 27  | 3                      |
| 2  | Mary | 77  | 1                      |
| 3  | Jack | 40  | 4                      |
+----+------+-----+------------------------+

+---------------------+
| relationship_status |
+----+----------------+
| id | name           |
+----+----------------+
| 1  | married        |
| 2  | widowed        |
| 3  | single         |
| 4  | divorced       |
+----+----------------+

在 SQLAlchemy 中定义(声明)表本身相对简单:

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)
    relationship_status_id = Column(Integer, ForeignKey('relationship_status.id'))


class RelationshipStatus(Base):
    __tablename__ = 'relationship_status'

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

初始化数据库时,可以使用Base.metadata.create_all(engine) 指令创建表。 user 表将在应用程序的运行生命周期内填充;但是,relationship_status 查找表的数据保持不变,将这些数据与表定义一起“声明”似乎是合适的。

然而,将数据持久化到表中自然需要session,并且与表定义本身不同,SQLAlchemy 似乎没有为给定表中的“预期行”提供任何声明性构造(当然,因为大多数表在任何应用程序都像 user 与动态数据)。

问题

使用 SQLAlchemy,如何在应用程序运行前声明查找表的模式和数据?理想情况下,该解决方案将涉及创建一些类似 Enum 的构造,其中包含应用程序其他部分可以引用的数据。

研究

SQLAlchemy 的创建者提出了the enum recipe。这种解决方案唯一明显的缺点是必须依赖正在使用的 DBMS 中的 enum 数据类型。对于这个问题的范围,首选独立于 DBMS 的查找表解决方案。

SQLAlchemy 的创建者还提出了一个相关的替代方案是the unique object recipe。这样的实现确保了查找表查询返回的行没有重复,但是仍然需要一个session 对象来进行任何声明或请求——模糊了数据库定义和实现之间的关注点分离。此外,客户端都只需要“只知道”要请求哪些行,而不是使用某种枚举(在 Python 中)以供参考。


问题的根源可能是概念性的,而不是与 SQLAlchemy 或 Python 相关。在任何一种情况下,任何建议都将不胜感激。

【问题讨论】:

    标签: python enums sqlalchemy


    【解决方案1】:

    首先,我认为在大多数情况下,在应用程序开发时恒定且已知的数据通常不适合存储在数据库中。我将使用基于 DBMS 的枚举或基于 Python 的枚举和检查约束来保证 users 表中的每一行都具有有效的关系状态。 既然你说你不会那样做,听起来你正在寻找一种方法来在创建你的 relationship_status 表时触发一些插入。 我已经调整 the after_create example 将某些内容插入到表中,而不是更改表。您应该能够对其进行调整以插入您的关系状态值。

    from sqlalchemy import event
    from sqlalchemy import Table, Column, Metadata, Integer
    
    m = MetaData()
    some_table = Table('some_table', m, Column('data', Integer))
    
    def after_create(target, connection, **kw):
        connection.execute("insert into  %s values ('1','single');" %
                                (target.name))
    
    event.listen(some_table, "after_create", after_create)
    

    【讨论】:

    • 您可以使用table():connection.execute(table(target.name).insert().values([{ 'name': 'single' }, ...])) 完全避免字符串格式化,这也允许将初始值定义为python 结构而不是内联到SQL 查询。
    • 感谢您对after_create触发器的引用;这似乎是最合适的解决方案。我对您的注释很感兴趣,即此类数据不适合存储在数据库中,我倾向于同意。但是,由于基于 DBMS 的枚举在系统之间不一致,对于上述情况,还有哪些替代方案?我的印象是查找表是公认的最佳实践。如何使用 python 枚举实现检查约束?
    猜你喜欢
    • 2016-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多