Ich lese über SQLalchemie und habe folgenden Code gesehen:
employees_table = Table('employees', metadata,
Column('employee_id', Integer, primary_key=True),
Column('name', String(50)),
Column('manager_data', String(50)),
Column('engineer_info', String(50)),
Column('type', String(20), nullable=False)
)
employee_mapper = mapper(Employee, employees_table, \
polymorphic_on=employees_table.c.type, polymorphic_identity='employee')
manager_mapper = mapper(Manager, inherits=employee_mapper, polymorphic_identity='manager')
engineer_mapper = mapper(Engineer, inherits=employee_mapper, polymorphic_identity='engineer')
Sollte ich 'type' zu einem int mit Konstanten in einer Bibliothek machen? Oder sollte ich einfach Typ zu einer Aufzählung machen?
python
sqlalchemy
Timmy
quelle
quelle
Die aufgezählten Typen von Python sind vom SQLAlchemy Enum-Typ ab SQLAlchemy 1.1 direkt akzeptabel :
import enum from sqlalchemy import Integer, Enum class MyEnum(enum.Enum): one = 1 two = 2 three = 3 class MyClass(Base): __tablename__ = 'some_table' id = Column(Integer, primary_key=True) value = Column(Enum(MyEnum))
Beachten Sie, dass oben die Zeichenfolgenwerte "eins", "zwei", "drei" beibehalten werden und nicht die ganzzahligen Werte.
Für ältere Versionen von SQLAlchemy habe ich einen Beitrag geschrieben, der einen eigenen Aufzählungstyp erstellt ( http://techspot.zzzeek.org/2011/01/14/the-enum-recipe/ ).
from sqlalchemy.types import SchemaType, TypeDecorator, Enum from sqlalchemy import __version__ import re if __version__ < '0.6.5': raise NotImplementedError("Version 0.6.5 or higher of SQLAlchemy is required.") class EnumSymbol(object): """Define a fixed symbol tied to a parent class.""" def __init__(self, cls_, name, value, description): self.cls_ = cls_ self.name = name self.value = value self.description = description def __reduce__(self): """Allow unpickling to return the symbol linked to the DeclEnum class.""" return getattr, (self.cls_, self.name) def __iter__(self): return iter([self.value, self.description]) def __repr__(self): return "<%s>" % self.name class EnumMeta(type): """Generate new DeclEnum classes.""" def __init__(cls, classname, bases, dict_): cls._reg = reg = cls._reg.copy() for k, v in dict_.items(): if isinstance(v, tuple): sym = reg[v[0]] = EnumSymbol(cls, k, *v) setattr(cls, k, sym) return type.__init__(cls, classname, bases, dict_) def __iter__(cls): return iter(cls._reg.values()) class DeclEnum(object): """Declarative enumeration.""" __metaclass__ = EnumMeta _reg = {} @classmethod def from_string(cls, value): try: return cls._reg[value] except KeyError: raise ValueError( "Invalid value for %r: %r" % (cls.__name__, value) ) @classmethod def values(cls): return cls._reg.keys() @classmethod def db_type(cls): return DeclEnumType(cls) class DeclEnumType(SchemaType, TypeDecorator): def __init__(self, enum): self.enum = enum self.impl = Enum( *enum.values(), name="ck%s" % re.sub( '([A-Z])', lambda m:"_" + m.group(1).lower(), enum.__name__) ) def _set_table(self, table, column): self.impl._set_table(table, column) def copy(self): return DeclEnumType(self.enum) def process_bind_param(self, value, dialect): if value is None: return None return value.value def process_result_value(self, value, dialect): if value is None: return None return self.enum.from_string(value.strip()) if __name__ == '__main__': from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, create_engine from sqlalchemy.orm import Session Base = declarative_base() class EmployeeType(DeclEnum): part_time = "P", "Part Time" full_time = "F", "Full Time" contractor = "C", "Contractor" class Employee(Base): __tablename__ = 'employee' id = Column(Integer, primary_key=True) name = Column(String(60), nullable=False) type = Column(EmployeeType.db_type()) def __repr__(self): return "Employee(%r, %r)" % (self.name, self.type) e = create_engine('sqlite://', echo=True) Base.metadata.create_all(e) sess = Session(e) sess.add_all([ Employee(name='e1', type=EmployeeType.full_time), Employee(name='e2', type=EmployeeType.full_time), Employee(name='e3', type=EmployeeType.part_time), Employee(name='e4', type=EmployeeType.contractor), Employee(name='e5', type=EmployeeType.contractor), ]) sess.commit() print sess.query(Employee).filter_by(type=EmployeeType.contractor).all()
quelle
Ich kenne mich in SQLAlchemy nicht wirklich aus, aber dieser Ansatz von Paulo schien mir viel einfacher zu sein.
Ich brauchte keine benutzerfreundlichen Beschreibungen, also habe ich mich dafür entschieden.
Zitat von Paulo (ich hoffe, es macht ihm nichts aus, wenn ich es hier erneut veröffentliche):
quelle
Hinweis: Folgendes ist veraltet. Sie sollten jetzt sqlalchemy.types.Enum verwenden, wie von Wolph empfohlen. Es ist besonders schön, da es PEP-435 seit SQLAlchemy 1.1 entspricht.
Ich mag das Rezept von zzzeek unter http://techspot.zzzeek.org/2011/01/14/the-enum-recipe/ , aber ich habe zwei Dinge geändert:
Beispiele:
class EmployeeType(DeclEnum): # order will be alphabetic: contractor, part_time, full_time full_time = "Full Time" part_time = "Part Time" contractor = "Contractor" class EmployeeType(DeclEnum): # order will be as stated: full_time, part_time, contractor full_time = EnumSymbol("Full Time") part_time = EnumSymbol("Part Time") contractor = EnumSymbol("Contractor")
Hier ist das modifizierte Rezept; Es verwendet die in Python 2.7 verfügbare OrderedDict-Klasse:
import re from sqlalchemy.types import SchemaType, TypeDecorator, Enum from sqlalchemy.util import set_creation_order, OrderedDict class EnumSymbol(object): """Define a fixed symbol tied to a parent class.""" def __init__(self, value, description=None): self.value = value self.description = description set_creation_order(self) def bind(self, cls, name): """Bind symbol to a parent class.""" self.cls = cls self.name = name setattr(cls, name, self) def __reduce__(self): """Allow unpickling to return the symbol linked to the DeclEnum class.""" return getattr, (self.cls, self.name) def __iter__(self): return iter([self.value, self.description]) def __repr__(self): return "<%s>" % self.name class DeclEnumMeta(type): """Generate new DeclEnum classes.""" def __init__(cls, classname, bases, dict_): reg = cls._reg = cls._reg.copy() for k in sorted(dict_): if k.startswith('__'): continue v = dict_[k] if isinstance(v, basestring): v = EnumSymbol(v) elif isinstance(v, tuple) and len(v) == 2: v = EnumSymbol(*v) if isinstance(v, EnumSymbol): v.bind(cls, k) reg[k] = v reg.sort(key=lambda k: reg[k]._creation_order) return type.__init__(cls, classname, bases, dict_) def __iter__(cls): return iter(cls._reg.values()) class DeclEnum(object): """Declarative enumeration. Attributes can be strings (used as values), or tuples (used as value, description) or EnumSymbols. If strings or tuples are used, order will be alphabetic, otherwise order will be as in the declaration. """ __metaclass__ = DeclEnumMeta _reg = OrderedDict() @classmethod def names(cls): return cls._reg.keys() @classmethod def db_type(cls): return DeclEnumType(cls) class DeclEnumType(SchemaType, TypeDecorator): """DeclEnum augmented so that it can persist to the database.""" def __init__(self, enum): self.enum = enum self.impl = Enum(*enum.names(), name="ck%s" % re.sub( '([A-Z])', lambda m: '_' + m.group(1).lower(), enum.__name__)) def _set_table(self, table, column): self.impl._set_table(table, column) def copy(self): return DeclEnumType(self.enum) def process_bind_param(self, value, dialect): if isinstance(value, EnumSymbol): value = value.name return value def process_result_value(self, value, dialect): if value is not None: return getattr(self.enum, value.strip())
quelle