Friday, September 15, 2017

Comparing SQLAlchemy Object Instances for Equality of Attributes

Leave a Comment

My Flask-Restful application has a number of "objects". In the first version of the app these are simple data structures with no behaviour, implemented as Dicts, or lists of Dicts.

The attributes of these "objects" can change. I use a generator function to track the changes, and then alert web-clients via server-sent-events (SSEs). This works by maintaining an "old" copy of the object to be tracked, and comparing it to the latest state.

In the next version of the app I populate the "objects" from a SQLite DB using SQLAlchemy. The objects are now implemented as SQLAlchemy declarative classes, or lists of such classes.

To compare "old" and "new" instances based on equality of attributes only I had to add an __eq__ override to my SQLAlchemy Objects. i.e. the instances are considered equal / unchanged when the attributes have the same values. (I have posted example code at the bottom of this question).

Technically this works, but raises some architectural alarm bells: Am I sailing in the wrong direction?

a) If I add __eq__ and __ne__ overrides to SQAlchemy objects, could this cause SQLAlchemy a problem when I later want to re-persist the objects back to the database?

b) How far into my application should the SQLAlchemy objects reach: is there a "pythonic best practice"? i.e. Is it ok / normal to extend SQLAlchemy objects with business logic / behaviours unconnected with DB persistence (such as tracking changes); or should they be used only as simple DTOs between the database and server, with business logic in other objects?

Note: it is clear to me that the data presented to the clients via the REST apis and the SSEs should be abstracted from the implementation details in the web-server and DB, so that is not part of this question.

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) 

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment