2012-11-18 2 views
6

Ich möchte wie diese sqlalchemy in einer Art und Weise nutzen:SQLAlchemy: return Objekt vorhandenen, anstatt eine neue zu schaffen, wenn Aufruf Konstruktor

email1 = EmailModel(email="[email protected]", account=AccountModel(name="username")) 
email2 = EmailModel(email="[email protected]", account=AccountModel(name="username")) 

Normalerweise sqlalchemy zwei Einträge für das Konto erstellen und verknüpfen jede E-Mail-Adresse Dies. Wenn ich den accountname als einzigartig einstelle, wirft sqlalchemy eine Exception, die mir sagt, dass bereits ein Eintrag mit demselben Wert existiert. Dies macht alles Sinn und funktioniert wie erwartet.

Nun dachte ich durch meine eigenen ein Ausweg, die den genannten Code ermöglicht und schafft nur ein nur einmal Konto durch die die neuen Constructor der AccountModel Klasse überschreiben:

def __new__(*cls, **kw): 
    if len(kw) and "name" in kw: 
     x = session.query(cls.__class__).filter(cls[0].name==kw["name"]).first() 
     if x: return x 
    return object.__new__(*cls, **kw) 

Dies funktioniert perfekt für mich. Aber die Frage ist:

  • Ist das der richtige Weg?
  • Gibt es einen sqlalchemy Weg, das gleiche zu erreichen?

Ich verwende die neueste 0.8.x SQLAlchemy Version und Python 2.7.x

Vielen Dank für jede Hilfe :)

Antwort

6

gibt es genau dieses Beispiel im Wiki bei http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject erstellen vorschlagen.

Obwohl in jüngster Zeit zog ich habe eine @classmethod dafür zu verwenden, anstatt den Konstruktor neu zu definieren, wie explizit als implizite besser ist, auch einfacher:

user.email = Email.as_unique('[email protected]') 

(Ich werde tatsächlich die Aktualisierung wiki jetzt, um die Nutzungsoptionen hier vollständiger darzustellen)

+0

Oukay, das ist genau das, was ich gesucht habe! –

1

Ich denke, es ist nicht der beste Weg, dies zu erreichen, da es sich um eine schafft Abhängigkeit des Konstruktors von der globalen Variablen session und ändert auch das Verhalten des Konstruktors auf unerwartete Weise (new wird erwartet, dass ein neues Objekt schließlich zurückgegeben wird). Wenn zum Beispiel jemand Ihre Klassen mit zwei Sitzungen parallel verwendet, wird der Code fehlschlagen und er muss sich in den Code einarbeiten, um den Fehler zu finden.

Ich bin nicht bekannt, dass „sqlalchemy“ Art und Weise, dies zu erreichen, aber ich würde eine Funktion createOrGetAccountModel wie

def createOrGetAccountModel(**kw): 
    if len(kw) and "name" in kw: 
     x = session.query(AccountModel).filter_by(name=kw["name"]).first() 
     if x: return x 
    return AccountModel(**kw) 
+0

Ihr Recht! Es ist nicht die perfekte Lösung in Bezug auf die Wartbarkeit des Codes. Aber ist __new__ nicht der perfekte Ort, um das Erschaffen eines Objekts zu manipulieren? –

+0

Ja, aber Sie erstellen (immer) keine neuen Objekte, also ist "__new__" irreführend. Wenn Sie 'x = SomeClass()' schreiben, würde jeder erwarten, dass 'x' ein neues Objekt ist ... – MartinStettner

Verwandte Themen