Ich habe viele Modellklassen mit Relationen zwischen ihnen mit einer CRUD-Schnittstelle zu bearbeiten. Das Problem besteht darin, dass einige Objekte nicht gelöscht werden können, da andere Objekte auf sie verweisen. Manchmal kann ich eine ON DELETE-Regel einrichten, um diesen Fall zu behandeln, aber in den meisten Fällen möchte ich nicht automatisch verwandte Objekte löschen, bis sie manuell gelöst werden. Wie auch immer, ich möchte dem Redakteur eine Liste von Objekten vorstellen, die sich auf das aktuell angezeigte beziehen, und diejenigen hervorheben, die das Löschen aufgrund der FOREIGN KEY-Einschränkung verhindern. Gibt es eine fertige Lösung, um Referer automatisch zu entdecken?Erkennen von References zu SQLAlchemy-Objekt
aktualisieren
Die Aufgabe scheint recht verbreitet zu sein (z django ORM zeigt alle Abhängigkeiten), so frage ich mich, dass es, um es noch keine Lösung ist.
Es gibt zwei Richtungen vorgeschlagen:
- Aufzählen alle Beziehungen des aktuellen Objekts und gehen durch ihre
backref
. Aber es gibt keine Garantie, dass alle Relationenbackref
definiert haben. Darüber hinaus gibt es einige Fälle, in denenbackref
bedeutungslos ist. Obwohl ich es überall definieren kann, mag ich es nicht so und es ist nicht zuverlässig. - (Vorgeschlagen von van und stephan) Überprüfen Sie alle Tabellen
MetaData
Objekt und sammeln Abhängigkeiten von ihrerforeign_keys
Eigenschaft (der Code sqlalchemy_schemadisplay kann als Beispiel verwendet werden, dank stephans Kommentare). Dies ermöglicht es, alle Abhängigkeiten zwischen Tabellen zu fangen, aber was ich brauche, ist Abhängigkeiten zwischen Modellklassen. Einige Fremdschlüssel sind in Zwischentabellen definiert und haben keine ihnen entsprechenden Modelle (in Relationen alssecondary
verwendet). Sicher, ich kann weiter gehen und verwandtes Modell finden (muss noch einen Weg finden, es zu tun), aber es sieht zu kompliziert aus.
Lösung
Hier ist eine Methode der Modellklasse Base (deklarative extention entworfen), die ich als Lösung verwenden. Es ist nicht perfekt und erfüllt nicht alle meine Anforderungen, aber es funktioniert für den aktuellen Stand meines Projekts. Das Ergebnis wird als Wörterbuch von Wörterbüchern gesammelt, sodass ich sie nach Objekten und ihren Eigenschaften gruppiert darstellen kann. Ich habe noch nicht entschieden, ob es eine gute Idee ist, da die Liste der Referer manchmal riesig ist und ich gezwungen bin, sie auf eine vernünftige Anzahl zu beschränken.
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
Dank an alle, die mir geholfen haben, besonders stephan und van.
Ich bin mir nicht sicher, ob ich die Frage verstehe. Tabellenobjekte haben eine 'foreign_keys' -Eigenschaft, die korrekt gesetzt werden sollte, wenn Sie die Metadaten durch Reflektion erhalten haben. ORM-Mapped-Klassen haben Relationen und Backrefs als Teil des Mappers. Kannst du es ausarbeiten? – stephan
@stephan: Ich habe die Frage aktualisiert, hoffentlich ist es jetzt klar. –
@Denis: Ja, jetzt viel klarer, und ich denke, van hat das meiste schon geschrieben. Bei einer gegebenen Modellklasse können Sie den Mapper mit der Funktion 'class_mapper()' oder 'object_mapper()' aufrufen. Dies gibt Ihnen die zugeordnete Tabelle. Dann können Sie die 'foreign_keys' dieser Tabellen aufrufen, um alle zugehörigen Tabellen zu erhalten. Für diese überprüfen Sie, welchen Klassen sie zugeordnet sind. Siehe das zweite Beispiel in http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SchemaDisplay für etwas Ähnliches. Ich kenne keinen besseren Weg. – stephan