Tengo muchas clases de modelos con ralaciones entre ellos con una interfaz CRUD para editar. El problema es que algunos objetos no se pueden eliminar ya que hay otros objetos que se refieren a ellos. A veces puedo configurar la regla ON DELETE para manejar este caso, pero en la mayoría de los casos no quiero que se eliminen automáticamente los objetos relacionados hasta que se desactiven manualmente. De todos modos, me gustaría presentarle al editor una lista de objetos que se refieren a la vista actual y resaltar aquellos que impiden su eliminación debido a la restricción FOREIGN KEY. ¿Hay una solución lista para descubrir automáticamente los referers?Descubriendo referers al objeto SQLAlchemy
actualización
la tarea parece ser bastante común (por ejemplo, Django ORM muestra todas las dependencias), por lo que se preguntan que no hay solución a ella todavía.
hay dos direcciones sugeridas:
- Enumerar todas las relaciones de objeto actual e ir a través de su
backref
. Pero no hay garantía de que todas las relaciones se hayan definido enbackref
. Además, hay algunos casos en los quebackref
no tiene sentido. Aunque puedo definirlo en todas partes, no me gusta hacerlo de esta manera y no es confiable. - (Sugerido por van y stephan) Compruebe todas las tablas del objeto
MetaData
y recopile dependencias de su propiedadforeign_keys
(el código de sqlalchemy_schemadisplay se puede usar como ejemplo, gracias a los comentarios de stephan). Esto permitirá detectar todas las dependencias entre tablas, pero lo que necesito son dependencias entre clases de modelo. Algunas claves externas se definen en tablas intermedias y no tienen modelos correspondientes (se usan comosecondary
en las relaciones). Claro, puedo ir más lejos y encontrar un modelo relacionado (tengo que encontrar la manera de hacerlo todavía), pero parece demasiado complicado.
Solución
continuación es un método de clase de modelo de base (diseñado para la extensión declarativa) que utilizo como solución. No es perfecto y no cumple con todos mis requisitos, pero funciona para el estado actual de mi proyecto. El resultado se recopila como diccionario de diccionarios, por lo que puedo mostrarlos agrupados por objetos y sus propiedades. Aún no he decidido si es una buena idea, ya que la lista de referers a veces es enorme y me veo obligado a limitarla a un número razonable.
def _get_referers(self):
db = object_session(self)
cls, ident = identity_key(instance=self)
medatada = cls.__table__.metadata
result = {}
# _mapped_models is my extension. It is collected by metaclass, so I didn't
# look for other ways to find all model classes.
for other_class in medatada._mapped_models:
queries = {}
for prop in class_mapper(other_class).iterate_properties:
if not (isinstance(prop, PropertyLoader) and \
issubclass(cls, prop.mapper.class_)):
continue
query = db.query(prop.parent)
comp = prop.comparator
if prop.uselist:
query = query.filter(comp.contains(self))
else:
query = query.filter(comp==self)
count = query.count()
if count:
queries[prop] = (count, query)
if queries:
result[other_class] = queries
return result
Gracias a todos los que me ayudaron, especialmente Stephan y Van.
No estoy seguro de entender la pregunta. Los objetos de tabla tienen una propiedad 'foreign_keys' que se debe establecer correctamente si obtuviste los metadatos por reflexión. Las clases mapeadas de ORM tienen relaciones y restituciones como parte del mapeador. ¿Puedes elaborar? – stephan
@stephan: He actualizado la pregunta, con suerte ahora está claro. –
@Denis: sí, mucho más claro ahora, y creo que van ya ha explicado la mayor parte. Dada una clase de modelo, puede obtener el asignador con la función 'class_mapper()' o 'object_mapper()'. Esto te da la tabla mapeada. Luego puede recorrer las 'foreign_keys' de estas tablas para obtener todas las tablas relacionadas. Para estos, comprueba a qué clases están asignados. Vea el segundo ejemplo en http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SchemaDisplay para algo similar. No sé de ninguna mejor manera. – stephan