2017-12-23 31 views
0

Ich habe ein Setup mit SQLAlchemy und Alembic Migrationen zusammen mit einem Postgres DB im Backend verwendet. Ich habe Enums in einigen DB-Modellen als Datentypen verwendet und ich habe den Enum-Type in SQLAlchemy und (deshalb) auch in Postgres verwendet. Während der fortlaufenden Entwicklung habe ich beschlossen, diese Enums durch Integer zu ersetzen, aus einigen kleineren Gründen (einschließlich höherer Flexibilität beim Hinzufügen neuer Werte, die eine DB-Migration erfordern würden, die den Datentyp ändert und diese in Alambic verändert, ist ziemlich kompliziert und kompliziert enums scheinen auf andere db-systeme weniger portierbar zu sein als ints sowieso). Aus diesem Grund muss ich eine Migration erstellen, die den Datentyp der enum-Spalten mithilfe von Alembic-Migrationen in int ändert.Postgres/SQLAlchemy/Alembic ändern Datentyp von enum zu int und zuordnen Wert mit

Leider habe ich noch keine Konvertierungsmethode gefunden, die es mir erlauben würde, die alten Werte während der Migration beizubehalten. Ich habe IntEnums verwendet, die den Enumerationswert auf Ganzzahlen in Python abbilden, aber Postgres verwendet dieses Mapping nicht intern, so dass es keine Informationen über den angenommenen Wert der Enumeration bei der Konvertierung in eine ganze Zahl enthält. Aus meiner Sicht muss ich irgendwie eine explizite Zuordnung von Enum-Name zu Integer zur Verfügung stellen, wenn ich die alter table-Abfrage anwende. Postgres stellt die using-Anweisung zur Verfügung, aber ich konnte nicht herausfinden, wie ich diesen Wert verwenden kann, um den Wert aus meinen enum-Werten den neuen/alten Integer-Werten zuzuordnen, die python ohnehin verwendet hat.

Wie also müsste eine solche using-Anweisung aussehen, wenn sie den alten (enumbasierten) Wert einem neuen (int-basierten) Wert zuordnen müsste, wenn ich manuell ein Mapping dafür bereitstellen müsste?

Ein Beispiel für einen solchen Enum:

class SexEnum(enum.IntEnum): 
    male = 0 
    female = 1 

Säule (alt im DB):

sex = db.Column(db.Enum(SexEnum)) 

Säule (neu):

sex = db.Column(db.Integer) 

Migration Befehl jetzt:

op.alter_column('users', 'sex', 
      type_=sa.Integer, postgresql_using='null') 

Null muss wahrscheinlich durch etwas anderes ersetzt werden.

Außerdem sollte angemerkt werden, dass es großartig wäre, wenn die Migration so kompatibel zu anderen DB-Systemen wie möglich wäre, was mich zwingen würde, sowieso ein anderes System als die using-Anweisung zu verwenden, oder?

+0

CASE Ausdruck wird wahrscheinlich dafür nützlich sein. –

Antwort

0

Okay, es gefunden. Danke an Ilja für den Tipp mit dem CASE.

Grundsätzlich ‚null‘ ersetzt mit

'(CASE sex WHEN \'male\'... END)' 

, die die Migration ohne leben brachte alle diese Werte in einer anderen Art und Weise einzustellen. Ich denke nicht, dass dies die Portabilitätsanforderung vollständig erfüllt, die ich hatte, einfach weil ich immer noch die using-Klausel von postgres verwende. Ansonsten funktioniert die einfache Case-Anweisung.