programacion privados poo orientada objetos metodos herencia comparar atributos python sqlalchemy

python - privados - Comparación de instancias de objetos SQLAlchemy para igualdad de atributos



programacion orientada a objetos python 3 (1)

Mi aplicación Flask-Restful tiene varios "objetos". En la primera versión de la aplicación, se trata de estructuras de datos simples sin comportamiento, implementadas como dictados o listas de dictados.

Los atributos de estos "objetos" pueden cambiar. Utilizo una función de generador para rastrear los cambios y luego alertar a los clientes web a través de los eventos enviados por el servidor (SSE). Esto funciona manteniendo una copia "antigua" del objeto que se va a rastrear, y comparándolo con el estado más reciente.

En la próxima versión de la aplicación, relleno los "objetos" de una base de datos SQLite usando SQLAlchemy. Los objetos ahora se implementan como clases declarativas SQLAlchemy, o listas de tales clases.

Para comparar instancias "antiguas" y "nuevas" basadas en la igualdad de atributos, solo tuve que agregar un reemplazo __eq__ a mis objetos SQLAlchemy. es decir, las instancias se consideran iguales / sin cambios cuando los atributos tienen los mismos valores. (He publicado código de ejemplo al final de esta pregunta).

Técnicamente esto funciona, pero levanta algunas alarmas arquitectónicas: ¿Estoy navegando en la dirección equivocada?

a) Si __ne__ reemplazos __eq__ y __ne__ a los objetos SQAlchemy, ¿podría esto causar un problema a SQLAlchemy cuando más tarde quiera volver a persistir los objetos en la base de datos?

b) ¿Qué tan lejos en mi aplicación deberían alcanzar los objetos de SQLAlchemy: hay una "mejor práctica pitónica"? es decir, ¿es correcto / normal extender los objetos SQLAlchemy con lógica / comportamiento empresarial desconectados con la persistencia de la base de datos (como los cambios de seguimiento)? o ¿deberían usarse solo como DTO simples entre la base de datos y el servidor, con lógica empresarial en otros objetos?

Nota: para mí es claro que los datos presentados a los clientes a través de las API REST y las ESEs se deben abstraer de los detalles de la implementación en el servidor web y el DB, por lo que no es parte de esta pregunta.

sqlalchemy id equidad frente a igualdad de referencia 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)


__eq__ en lo que está sucediendo detrás de la clase Base, para mostrar que los __eq__ y __ne__ están bien. Cuando crea una instancia de su clase Base llamando a declarative_base() , está usando una metaclase detrás de escena para configurarlo (puede valer la pena leer esta explicación esta explicación de metaclase para comprender mejor por qué está involucrada). Hace una configuración configurable, como agregar un constructor personalizado a su clase Base y configurar cómo se asignará del objeto a una tabla.

declarative_base() luego devolverá una nueva instancia de clase Base de una metaclase DeclarativeMeta . La razón principal por la que se involucran las metaclases es que cuando crea una clase que extiende su Base , la asignará a una tabla. Si rastrea un poco esta ruta, verá cómo asigna las columnas que declara en su objeto a una tabla.

self.cls.__mapper__ = mp_ = mapper_cls( self.cls, # cls is your model self.local_table, **self.mapper_args # the columns you have defined )

Aunque el Mapeador real que está haciendo esto parece que se vuelve muy complicado y de bajo nivel, en esta etapa está operando con claves primarias y columnas en lugar de instancias de objetos reales. Sin embargo, esto no confirma que nunca se haya usado, así que examiné los usos de == y != En la fuente y no vi ninguna causa de preocupación.

En cuanto a tu segunda pregunta, solo puedo ofrecer mi propia opinión: he buscado en Google este tema muchas veces en el pasado y no he encontrado mucho en el uso de la Alquimia SQL "estándar de oro". He usado SQL Alchemy para un par de proyectos hasta el momento y parece que su uso de los objetos puede extenderse tanto como lo que puede abstraer el ciclo de vida de la session . Para mí, parece que la "magia" de Alquimia está bastante alejada de los modelos en sí mismos, que cuando las sesiones se manejan bien, están lo suficientemente alejadas de la capa de datos como para que no parezca que la lógica de negocios en las clases entraría la manera.