2016-08-19 34 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。对我来说,似乎有足够的炼金术“魔力”从模型本身抽象出来,当会话处理得很好时,它们离数据层足够远,以至于不会觉得类中的业务逻辑会得到方式。