2010-03-05 23 views
15

在設置屬性之後(或之後),但在會話提交之前,是否有辦法對對象執行驗證?有沒有辦法在SQLAlchemy對象上透明地執行驗證?

例如,我有一個域模型Device具有mac屬性。我想確保mac屬性在添加到數據庫或在數據庫中更新之前包含有效且已過濾的mac值。

它看起來像Pythonic方法是做大部分東西作爲屬性(包括SQLAlchemy)。如果我使用PHP或Java編寫了代碼,我可能會選擇創建getter/setter方法來保護數據,併爲我提供在域模型本身中處理此問題的靈活性。

public function mac() { return $this->mac; } 
public function setMac($mac) { 
    return $this->mac = $this->sanitizeAndValidateMac($mac); 
} 
public function sanitizeAndValidateMac($mac) { 
    if (! preg_match(self::$VALID_MAC_REGEX)) { 
     throw new InvalidMacException($mac); 
    } 
    return strtolower($mac); 
} 

什麼是使用SQLAlchemy來處理這種情況的Pythonic方法? (雖然我知道驗證,應該在其他地方(即網絡框架)處理我想弄清楚如何處理這些領域具體的驗證規則的一些,因爲他們必然會經常出現)。

UPDATE

我知道,我可以用property做到這一點在正常情況下。關鍵部分是我正在使用這些類的SQLAlchemy。我不明白SQLAlchemy如何執行它的魔法,但我懷疑創建和重寫這些屬性可能會導致不穩定和/或不可預知的結果。

回答

2

「它看起來像Python化的做法是辦最多的事作爲屬性」

有異,但很接近。

「如果我在PHP或Java編碼的這一點,我可能會選擇創建getter/setter方法......」

好。這足夠Pythonic。你的getter和setter函數綁定在一個屬性中;這很不錯。

什麼問題?

你在問怎麼拼寫property

但是,「透明驗證」 - 如果我正確地閱讀了您的示例代碼 - 可能並不真的是一個好主意。

您的模型和您的驗證應該保持分開。對單個模型進行多重驗證是很常見的。對於某些用戶,字段是可選的,固定的或不使用的;這導致多重驗證。

按照使用Form進行驗證的Django設計模式,您會更高興,它與模型分開。

+2

我不知道什麼樣的神奇的SQLAlchemy的使用綁定到模型類的屬性。我不會認爲在我的類上定義我自己的'mac = property()'是安全的。我認爲我的問題是,這是安全的嗎?如果是這樣,是否有任何陷阱?如果不是,還有什麼其他的選擇? – 2010-03-06 07:07:04

+0

沒有魔法。這不是陷阱。另一種方法是我們通常所做的:我們在模型類之外進行驗證*,使得它更簡單。在模型外定義你的驗證*,然後你不必擔心這一點。 – 2010-03-07 05:07:31

7

是的。這可以使用MapperExtension很好地完成。

# uses sqlalchemy hooks to data model class specific validators before update and insert 
class ValidationExtension(sqlalchemy.orm.interfaces.MapperExtension): 
    def before_update(self, mapper, connection, instance): 
     """not every instance here is actually updated to the db, see http://www.sqlalchemy.org/docs/reference/orm/interfaces.html?highlight=mapperextension#sqlalchemy.orm.interfaces.MapperExtension.before_update""" 
     instance.validate() 
     return sqlalchemy.orm.interfaces.MapperExtension.before_update(self, mapper, connection, instance) 
    def before_insert(self, mapper, connection, instance): 
     instance.validate() 
     return sqlalchemy.orm.interfaces.MapperExtension.before_insert(self, mapper, connection, instance) 


sqlalchemy.orm.mapper(model, table, extension = ValidationExtension(), **mapper_args) 

您可能要檢查before_update參考因爲這裏不是每個實例實際更新到數據庫。

13

您可以使用裝飾器@validates()在SQLAlchemy類中添加數據驗證。

從文檔 - Simple Validators

的屬性驗證可引發異常,停止變異屬性值的過程中,或可改變給定值到不同的東西。

from sqlalchemy.orm import validates 

class EmailAddress(Base): 
    __tablename__ = 'address' 

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

    @validates('email') 
    def validate_email(self, key, address): 
     # you can use assertions, such as 
     # assert '@' in address 
     # or raise an exception: 
     if '@' not in address: 
      raise ValueError('Email address must contain an @ sign.') 
     return address 
+0

只是一個簡單的問題:如果我想要簡單的「存在」驗證,我應該在列聲明中添加'nullable = false',然後嘗試捕獲'session.commit()'錯誤?或者我應該嘗試一個類似的驗證器?謝謝。 – 2015-08-10 08:57:23

相關問題