2017-06-04 31 views
3

动机

以一个简单的例子,其中需要的数据的列通过一个枚举类型在SQL来表示:如何在SQLAlchemy中声明和初始化查找表数据?

+------------------------------------------+ 
| 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。在任何情况下,任何建议将不胜感激。

回答

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) 
+0

您可以避免使用['table()'](http://docs.sqlalchemy)完全排除字符串格式。org/en/latest/core/selectable.html#sqlalchemy.sql.expression.table):'connection.execute(table(target.name).insert()。values([{'name':'single'}, ...]))',这也允许将初始值定义为python结构而不是内联SQL查询。 –

+0

感谢您对'after_create'触发器的引用;它似乎是最合适的解决方案。我对你的提示很感兴趣,这些数据不适合存储在数据库中,我倾向于同意。但是,在基于DBMS的枚举在各个系统之间不一致的情况下,还有什么替代方案可用于上述情况?我的印象是查询表是公认的最佳实践。如何使用python枚举检查约束? – RNanoware