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