我的Flask-Restful应用有很多“对象”。在应用的第一个版本中,这些对象是简单的数据结构,没有行为,实现为字典或字典列表。
这些“对象”的属性可能会发生变化。我使用生成器函数来跟踪这些变化,然后通过服务器发送事件(SSE)通知Web客户端。 这是通过维护要跟踪的对象的“旧”副本,并将其与最新状态进行比较来实现的。
在应用的下一个版本中,我使用SQLAlchemy从SQLite DB中填充“对象”。 现在,这些对象是作为SQLAlchemy声明性类或此类类的列表实现的。
为了仅基于属性相等性比较“旧”和“新”实例,我必须添加__eq__
覆盖到我的SQLAlchemy对象中。
也就是说,当属性具有相同的值时,实例被认为是相等/未更改的。(我已经在本问题底部发布了示例代码。)
技术上,这可以工作,但引发了一些架构警报:我是否朝着错误的方向前进?
a)如果我为SQAlchemy对象添加__eq__
和__ne__
覆盖,那么当我稍后想重新持久化对象到数据库时,
这会引起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://dev59.com/H3RC5IYBdhLWcg3wKtz2
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)
__eq __()
例程,逐个比较您关心的实际属性。 - zzzeek