Einstellung löschen-Waise auf SQLAlchemy Beziehung führt zu AssertionError: Diese AttributeImpl ist nicht konfiguriert zu verfolgen Eltern
dies ist meine Flask-SQLAlchemy Deklarative code:
from sqlalchemy.ext.associationproxy import association_proxy
from my_flask_project import db
tagging = db.Table('tagging',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id', ondelete='cascade'), primary_key=True),
db.Column('role_id', db.Integer, db.ForeignKey('role.id', ondelete='cascade'), primary_key=True)
)
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
def __init__(self, name=None):
self.name = name
@classmethod
def delete_orphans(cls):
for tag in Tag.query.outerjoin(tagging).filter(tagging.c.role_id == None):
db.session.delete(tag)
class Role(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='cascade'))
user = db.relationship('User', backref=db.backref('roles', cascade='all', lazy='dynamic'))
...
tags = db.relationship('Tag', secondary=tagging, cascade='all', backref=db.backref('roles', cascade='all'))
tag_names = association_proxy('tags', 'name')
__table_args__ = (
db.UniqueConstraint('user_id', 'check_id'),
)
Grundsätzlich, es ' s viele-zu-viele-Kennzeichnung mit Deklarativen. Beim löschen einiger Einträge aus-tagging, ich will SQLAlchemy zum Aufräumen des Waisen. Wie ich in Google docs, um dieses feature zu aktivieren, sollte ich dies tun:
class Role(db.Model):
...
tags = db.relationship('Tag', secondary=tagging, cascade='all,delete-orphan', backref=db.backref('roles', cascade='all'))
...
Jedoch, eine solche Einstellung führt zu AssertionError: Diese AttributeImpl ist nicht konfiguriert zu verfolgen Eltern. Ich habe es gegoogelt und nichts gefunden, außer der opensourced code von SQLAlchemy. Daher habe ich die classmethod Tag.delete_orphans()
(es ist im obigen code) aufrufen, um es jedes mal, wenn ich denke, einige Waisen, die auftreten konnten, aber das scheint nicht sehr elegant.
Irgendwelche Ideen oder Erklärungen, warum meine Einstellung mit delete-orphan
funktioniert nicht?
Du musst angemeldet sein, um einen Kommentar abzugeben.
OK, in diesem Fall müssen Sie genauer hinsehen, aber es ist eine Warnung, dass hier möglicherweise eine Ausnahme geworden, und ich werde in diesem Blick. Hier ist eine funktionierende version von deinem Beispiel:
Nun laufen lasst:
So, hier ist der wichtige Teil: SAWarning: Auf Rolle.tags -, delete-orphan cascade nicht unterstützt, auf eine viele-zu-viele oder viele-zu-eins-Beziehung, wenn single_parent ist nicht festgelegt. Set single_parent=True auf die Beziehung().
Damit der Fehler behoben ist, wenn Sie sagen:
Aber, das Sie beobachten können, dass das nicht wirklich das, was Sie wollen:
Ausgabe:
Dass Ihre "alleinerziehende" - die "delete-orphan" - Funktion funktioniert nur mit dem, was heißt ein lifecycle Beziehung, wo das Kind besteht ausschließlich im Rahmen der single-Eltern. Es gibt also praktisch keinen Sinn, mit einer viele-zu-viele " mit "orphan", und es ist nur unterstützt, weil einige Leute wirklich, wirklich wollte, um dieses Verhalten mit einer Zuordnung Tabelle unabhängig (legacy-DB-Zeug, vielleicht).
Heres der doc für die:
Was ist impliziert, wenn Sie sagen, "ich will es zu reinigen, die Waisen" ? Es würde hier bedeuten, dass, wenn Sie sagen
r1.tags.remove(t1)
, dann Sie sagte, "flush". SQLAlchemy sehen würde, "r1.tags t1 entfernt wurde, und wenn es eine Waise müssen wir löschen!!! OK, also lasst uns gehen, "tagging" und dann scan die gesamte Tabelle für alle Einträge, die bleiben. "Um dies naiv für jeden tag-in einer Zeit, klar wäre wirklich ineffizient, wenn Sie betroffen sind ein paar hundert tag-Sammlungen in einer Sitzung, da würde es ein paar hundert von diesen potenziell enorme Abfragen. Zu tun, um so weniger, als naiv wäre eine ziemlich komplizierte Funktion hinzufügen, wie die Einheit der Arbeit neigt dazu, zu denken, in Bezug auf die Sammlung zu einem Zeit - und es würde noch hinzufügen, spürbar Abfrage overhead, dass die Leute vielleicht wirklich nicht wollen. Die Einheit der Arbeit tut, was es tut wirklich gut, doch er versucht, sich aus dem Geschäft der ungewöhnliche Grenzfälle, die add viel Komplexität und überraschungen. In der Realität, die "delete-orphan" - system kommt nur ins Spiel, wenn ein Objekt B ist losgelöst von einem Objekt im Speicher - es gibt keinen scan der Datenbank, oder ähnliches, es ist viel einfacher als das - und die flush-Prozess hat um die Dinge so einfach wie möglich.Also, was machst du hier mit "löschen " Waisen" ist auf dem richtigen Weg, aber wir stecken Sie in ein Ereignis, und verwenden auch eine effizientere Abfrage und löschen alles was wir nicht brauchen, in einem Rutsch:
nun mit jedem flush bekommen wir diese Abfrage am Ende:
Also brauchen wir nicht zum ziehen von Objekten in den Speicher, um Sie zu löschen, wenn wir löschen können, auf eine einfache SQL-Kriterium (unter Berufung auf das ziehen von Zeilen in den Speicher, wenn die Datenbank kann über Operationen effizienter wurde als Reihe von qualvollen Zeile Programmierung). Die "not EXISTS" funktioniert sehr gut, wenn die Suche für das fehlen einer zusammenhängenden Reihe zu, im Vergleich zu den OUTER-JOIN, die tendenziell teurer werden die Planer.