2016-08-19 72 views
15

我的Flask-Restful應用程序有一些「對象」。在應用程序的第一個版本中,這些簡單的數據結構 沒有任何行爲,實現爲Dicts或Dicts列表。比較SQLAlchemy對象實例的屬性平等

這些「對象」的屬性可以改變。我使用生成器函數來跟蹤更改,然後通過服務器發送事件(SSE)來提醒Web客戶端。 這可以通過保持要跟蹤的對象的「舊」副本並將其與最新狀態進行比較來實現。

在應用程序的下一個版本中,我使用SQLAlchemy從SQLite數據庫填充「對象」。 這些對象現在以SQLAlchemy聲明式類或這些類的列表形式實現。

爲了比較基於屬性相等的「舊」和「新」實例,只需要將__eq__覆蓋添加到我的SQLAlchemy對象 。即當屬性具有相同的值時,實例被認爲是相同/不變的。 (我在這個問題的底部發布了示例代碼)。

從技術上講,這是有效的,但引發了一些建築警鐘:我是否在錯誤的方向航行?

一)如果我添加__eq____ne__覆蓋到SQAlchemy對象,這可能導致SQLAlchemy的一個問題,當我後來想 重新持久化對象回數據庫?

b)SQLAlchemy對象到達應用程序的距離有多遠:是否有「pythonic最佳實踐」?即擴展具有與DB持久性無關的業務邏輯/行爲的SQLAlchemy對象(例如跟蹤更改)是正常的還是正常的;還是應該將它們僅用作數據庫和服務器之間的簡單DTO,以及其他對象中的業務邏輯?

注意:我很清楚,通過REST API和SSE呈現給客戶端的數據應該從Web服務器和數據庫中的實現細節中抽象出來,所以這不是這個問題的一部分。

sqlalchemy id equality vs reference equality https://codereview.stackexchange.com/questions/93511/data-transfer-objects-vs-entities-in-java-rest-server-application http://www.mehdi-khalili.com/orm-anti-patterns-part-4-persistence-domain-model/

class EqualityMixin(object): 
# extended from the concept in : 
# https://stackoverflow.com/questions/390250/elegant-ways-to-support-equivalence-equality-in-python-classes 

    def __eq__(self, other): 
     classes_match = isinstance(other, self.__class__) 
     a, b = deepcopy(self.__dict__), deepcopy(other.__dict__) 
     #compare based on equality our attributes, ignoring SQLAlchemy internal stuff 
     a.pop('_sa_instance_state', None) 
     b.pop('_sa_instance_state', None) 
     attrs_match = (a == b) 
     return classes_match and attrs_match 

    def __ne__(self, other): 
     return not self.__eq__(other) 

回答

1

我會深入到發生了什麼Base類的後面,以表明__eq____ne__覆蓋的罰款。當你通過調用declarative_base()實例化你的Base類時,它在幕後使用元類來設置它(可能值得閱讀這個解釋this metaclass explanation以更好地理解爲什麼涉及它)。它有一些可配置的設置,比如向你的Base類中添加一個自定義構造函數,並設置它如何從對象映射到表。

declarative_base()然後將返回DeclarativeMeta元類的新的Base類實例。這裏涉及的元類的全部原因是,當你創建一個擴展你的類的類時,它將把它映射到一個表。如果你稍微追蹤這條路徑,你會看到它如何將你在對象上聲明的列映射到表。

self.cls.__mapper__ = mp_ = mapper_cls(
     self.cls, # cls is your model 
     self.local_table, 
     **self.mapper_args # the columns you have defined 
    ) 

雖然實際的映射這是做這看起來像它變得非常複雜和低的水平,在這個階段,它與主鍵和列,而不是實際的對象實例運行。但是,這並不能證實它從未被使用過,所以我查看了==!=的使用情況,並沒有看到任何引起關注的原因。

至於你的第二個問題,我只能真正提供我自己的觀點 - 我過去多次圍繞這個主題進行了搜索,並沒有找到太多的'金標準'SQL鍊金術的用法。到目前爲止,我已經使用SQL Alchemy開展了幾個項目,感覺就像你對這些對象的使用可以擴展到儘可能明智地抽象出生命週期的session。對我來說,似乎有足夠的鍊金術「魔力」從模型本身抽象出來,當會話處理得很好時,它們離數據層足夠遠,以至於不會覺得類中的業務邏輯會得到方式。