2013-10-26 30 views
3

比方說,我有以下結構(使用燒瓶的SQLAlchemy):SQLAlchemy的:自參考默認值作爲查詢

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String, nullable=False, index=True) 
    # The following line throws an error at runtime. 
    variant = db.Column(db.Integer, nullable=False, index=True, 
         default=select(func.count(User.id)).where(User.name == self.name)) 

    def __init__(self, name): 
     super(User, self).__init__() 
     self.name = name 

    @property 
    def clause(self): 
     return '/'.join([str(self.variant), self.name]) 

問題是,「用戶是沒有定義。」我想模擬一個系統,用戶可以選擇相同的名稱,但添加一個字段以系統化的方式區分用戶,而不使用(從而暴露)「ID」字段。

任何人都知道如何使用自引用查詢來填充默認值?

回答

5

在用戶可用時,只需將「default」分配給列即可解決此處未提及用戶的默認問題。然而,這並不能解決問題,因爲「自我」意味着什麼也沒有,沒有用戶方法被調用,所以你不能只引用「自我」。這條語句所面臨的挑戰是,您希望將它作爲內聯子SELECT呈現,但它仍需要知道「.name」的內存中值。所以你必須以某種方式分配每個對象的子SELECT。

人們通常使用before_insert處理程序來處理ORM級INSERT的默認方式。

另一個值得指出的方法是創建一個SQL級別的INSERT觸發器。這是總體上最「傳統」的方法,因爲您需要訪問所插入的行;觸發器定義了一種獲取正在插入的行值的方法。

至於在列級別使用默認值,您需要使用可調用的函數作爲默認值,它可以查看所插入行的當前值,但此時這意味着您的SELECT語句將不會與INSERT語句內聯呈現,您需要預先執行SELECT,這不是我們想要的。

無論如何,將SQL表達式呈現到INSERT中同時使該SQL表達式引用某個本地按對象狀態的基本任務是通過將該表達式分配給該屬性來實現的,ORM在刷新時間。下面我們在構造函數中這樣做,但是這也可以發生在before_insert()內部:

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class User(Base): 
    __tablename__ = 'user' 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, index=True) 
    variant = Column(Integer, nullable=False, index=True) 

    def __init__(self, name): 
     self.name = name 
     self.variant = select([func.count(User.id)]).where(User.name == self.name) 

e = create_engine("sqlite://", echo=True) 

Base.metadata.create_all(e) 

s = Session(e) 

s.add(User(name='n1')) 
s.commit() 

s.add(User(name='n1')) 
s.commit() 

print s.query(User.variant).all() 
+0

謝謝先生!將嘗試before_insert方法。 – wheaties