我的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)