2017-06-13 112 views
0

我們正在爲使用龍捲風和sqlalchemy的應用程序創建服務。該應用程序使用django編寫,並使用「軟刪除機制」。這意味着在底層的mysql表中沒有刪除。要將行標記爲已刪除,我們只需將屬性「delete」設置爲True即可。但是,在我們使用sqlalchemy的服務中。一開始,我們就開始通過SQLAlchemy中做出自己喜歡的查詢,添加檢查刪除:使用sqlalchemy實施「軟刪除」系統

customers = db.query(Customer).filter(not_(Customer.deleted)).all() 

然而,這導致很多潛在的錯誤,因爲開發商往往錯過了在那裏查詢,刪除了檢查。因此,我們決定與我們的查詢類,做了「預過濾器」來覆蓋默認查詢:

class SafeDeleteMixin(Query): 
    def __iter__(self): 
     return Query.__iter__(self.deleted_filter()) 
    def from_self(self, *ent): 
     # override from_self() to automatically apply 
     # the criterion too. this works with count() and 
     # others. 
     return Query.from_self(self.deleted_filter(), *ent) 
    def deleted_filter(self): 
     mzero = self._mapper_zero() 
     if mzero is not None: 
      crit = mzero.class_.deleted == False 
      return self.enable_assertions(False).filter(crit) 
     else: 
      return self 

這從SQLAlchemy的文檔解決方案在這裏啓發:

https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery 

然而,我們仍然面臨的問題,比如在我們一起進行過濾和更新以及使用上面定義的這個查詢類的情況下,當應用更新過濾器時,更新不遵守delete=False的標準。

db = CustomSession(with_deleted=False)() 
result = db.query(Customer).filter(Customer.id == customer_id).update({Customer.last_active_time: last_active_time }) 

我如何能實現在SQLAlchemy的

回答

1

的「軟刪除」功能,我在這裏做了類似的事情。我們做了一點不同,我們創建了一個所有數據庫訪問都經過的服務層,類似於控制器,但僅用於數據庫訪問,我們稱之爲ResourceManager,它受到「域驅動設計」(偉大的書籍)的啓發,對於使用SQLAlchemy來說是非常寶貴的)。派生的ResourceManager存在於每個聚合根,即。每個資源類你想通過的東西。 (儘管有時候對於非常簡單的ResourceManagers來說,派生管理器類本身是動態生成的)它有一個方法可以發出基本查詢,並且該基本查詢在發送之前會被軟件刪除。從此,您可以生成該查詢進行篩選,最後使用query.one()或first()或all()或count()調用它。請注意,我遇到過這種生成查詢處理的一個問題,如果您多次加入表,則可以掛起自己。在某些情況下,我們必須跟蹤哪些表已經加入。如果您的刪除過濾器不在主表中,只需先過濾即可,之後您就可以加入。

所以是這樣的:

class ResourceManager(object): 
    # these will get filled in by the derived class 
    # you could use ABC tools if you want, we don't bother 
    model_class = None 
    serializer_class = None 

    # the resource manager gets instantiated once per request 
    # and passed the current requests SQAlchemy session 
    def __init__(self, dbsession): 
     self.dbs = dbsession 

    # hand out base query, assumes we have a boolean 'deleted' column 
    @property 
    def query(self): 
     return self.dbs(self.model_class).filter(
      getattr(self.model_class, 'deleted')==False) 

class UserManager(ResourceManager): 
    model_class = User 

# some client code might look this 
dbs = SomeSessionFactoryIHave() 
user_manager = UserManager(dbs) 
users = user_manager.query.filter_by(name_last="Duncan").first()   

現在只要我總是通過一個ResourceManager,它有其他好處也打算開始(見上述書),我知道我的查詢是預過濾。對於我們當前的一個軟刪除和相當廣泛且棘手的數據庫模式的項目來說,這非常有效。

hth!

0

我會創造一個功能

def customer_query(): 
    return db.session.query(Customer).filter(Customer.deleted == False) 

我使用的查詢功能,不要忘了默認的標誌,根據用戶的權限設置標誌,過濾器使用連接等,所以這些東西不會是複製粘貼和遺忘在各個地方。

+0

這不會停止查詢沒有刪除,這是至關重要的。因爲整個觀點是避免錯誤。 – dusual

+0

'customer_query().filter(something).update(something2)'應該將刪除過濾器和'something'過濾器一起應用。 – aitchnyu