2017-06-04 64 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