[SQLAlchemy] object duplizieren

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Ich möchte ein Objekt (also eine Tabellenzeile) duplizieren.

Code: Alles auswählen

obj2 = obj1.duplicate()
'obj2' soll also alle Felder/Spalten-Werte haben, wie 'obj1' mit Ausnahme des PrimaryKeys, weil dieser ja unique sein muss. Gibt es sowas schon in der lib, oder muss ich mir das selbst basteln?

Mein Problem mit der Doku hierbei ist, dass ich zu der Basisklasse (declarative_base()) keine Doku finden kann.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@MoonKid: ich könnte mir vorstellen, dass es keine Methode dafür gibt, liegt daran, dass es so gut wie keinen Anwendungsfall dafür gibt. Meist sind die Abhängigkeiten zwischen verschiedenen Tabellen doch komplizierter, als dass man einfach eine Kopie machen könnte. Warum auch, wenn es den Eintrag in der Datenbank schon gibt.
BlackJack

@MoonKid: Die Basisklasse die von `declarative_base()` dynamisch erstellt wird, besteht im Grund nur aus dem Erstellen eines `metadata`-Attributs und der Metaklasse die für die ”Magie” zuständig ist aus den Klassenattributen von Unterklassen dieses Attribut entsprechend mit Daten zu versorgen. Also zum Beispiel das `Table`-Objekt aus `__tablename__`, den `Column`-Exemplaren & Co zu erstellen und `metadata` bekannt zu machen.

`obj1` hat ja ein `__mapper__`-Attribut das für das Abbilden von Properties auf die Datenbank zuständig ist. Anhand dessen kannst Du Dir so eine Funktion, zumindest für einfache Fälle leicht selber schreiben. Völlig ungetestet:

Code: Alles auswählen

    def duplicate(self):
        arguments = dict()
        for name, column in self.__mapper__.columns.items():
            if not (column.primary_key or column.unique):
                arguments[name] = getattr(self, name)
        return self.__class__(**arguments)
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

https://stackoverflow.com/questions/146 ... hed-object

make_transient() könnte eine Lösung sein. Werde es probieren.

Verstehe aber in dem obigen Beispiel nicht, warum ich noch expunge() aufrufen sollte.
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

BlackJack hat geschrieben:Völlig ungetestet:

Code: Alles auswählen

    def duplicate(self):
        arguments = dict()
        for name, column in self.__mapper__.columns.items():
            if not (column.primary_key or column.unique):
                arguments[name] = getattr(self, name)
        return self.__class__(**arguments)
Auf der sqlalchemy-Liste wurde auch dieser Vorschlag gemacht

Code: Alles auswählen

from sqlalchemy import inspect

mapper = inspect(MyClass)

new_obj = MyClass()
for attr in mapper.attrs:
    setattr(new_obj, attr.key, getattr(old_obj, attr.key))
MoonKid
User
Beiträge: 105
Registriert: Mittwoch 10. Dezember 2014, 16:24

Scheinbar eine Lösung.
Antworten