C'è un modo per definire una colonna (chiave primaria) come UUID in SQLAlchemy se si utilizza PostgreSQL (Postgres)?Come posso utilizzare gli UUID in SQLAlchemy?
risposta
Si potrebbe provare a scrivere un custom type, per esempio:
import sqlalchemy.types as types
class UUID(types.TypeEngine):
def get_col_spec(self):
return "uuid"
def bind_processor(self, dialect):
def process(value):
return value
return process
def result_processor(self, dialect):
def process(value):
return value
return process
table = Table('foo', meta,
Column('id', UUID(), primary_key=True),
)
Questo non ha nemmeno lavoro, è solo un lavoro di taglia e incolla dal tipo di esempio fittizio dalla documentazione. La risposta di Tom Willis è molto meglio. –
Oltre a [risposta di Florian] (http://stackoverflow.com/questions/183042/how-can-i-use-uuids-in-sqlalchemy/188427#188427), c'è anche [questo blog] (http: //blog.sadphaeton.com/2009/01/19/sqlalchemy-recipeuuid-column.html). Sembra simile con la differenza che le sottoclassi 'types.TypeDecorator' invece di' types.TypeEngine'. L'uno o l'altro approccio ha un vantaggio o uno svantaggio rispetto all'altro? –
Non ha bisogno di un 'default =?'? per esempio. 'Colonna ('id', UUID(), primary_key = True, default =
I wrote this e il dominio è andato, ma qui è il coraggio ....
Indipendentemente da come i miei colleghi che realmente si preoccupano e propria banca dati aspetto del design di UUID e GUID utilizzati per i campi chiave. Spesso trovo che ho bisogno di farlo. Penso che abbia alcuni vantaggi rispetto all'autoincremento che ne valga la pena.
Sono stato Perfezionamento di una tipo di colonna UUID per gli ultimi mesi e penso di aver finalmente capito solido.
from sqlalchemy import types
from sqlalchemy.dialects.mysql.base import MSBinary
from sqlalchemy.schema import Column
import uuid
class UUID(types.TypeDecorator):
impl = MSBinary
def __init__(self):
self.impl.length = 16
types.TypeDecorator.__init__(self,length=self.impl.length)
def process_bind_param(self,value,dialect=None):
if value and isinstance(value,uuid.UUID):
return value.bytes
elif value and not isinstance(value,uuid.UUID):
raise ValueError,'value %s is not a valid uuid.UUID' % value
else:
return None
def process_result_value(self,value,dialect=None):
if value:
return uuid.UUID(bytes=value)
else:
return None
def is_mutable(self):
return False
id_column_name = "id"
def id_column():
import uuid
return Column(id_column_name,UUID(),primary_key=True,default=uuid.uuid4)
# Usage
my_table = Table('test',
metadata,
id_column(),
Column('parent_id',
UUID(),
ForeignKey(table_parent.c.id)))
ritengo memorizzazione come binario (16 byte) dovrebbe finire per essere più efficiente rispetto alla rappresentazione di stringa (36 byte?) E sembra esserci qualche indicazione che l'indicizzazione 16 blocchi byte dovrebbe essere più efficiente in mysql di stringhe. Non mi aspetterei che fosse peggio comunque.
Uno svantaggio che ho trovato è che almeno in phpymyadmin, non è possibile modificare i record perché tenta implicitamente di fare una sorta di conversione dei caratteri per "select * dalla tabella dove id = ..." e non c'è vari problemi di visualizzazione.
Oltre a ciò tutto sembra funzionare bene, e quindi lo sto lanciando là fuori. Lascia un commento se vedi un errore evidente con esso. Accolgo con favore qualsiasi suggerimento per migliorarlo.
A meno che non mi manca qualcosa la soluzione di cui sopra funziona se il database sottostante ha un tipo di UUID. In caso contrario, verrebbero probabilmente visualizzati errori quando viene creata la tabella. La soluzione che avevo in mente riguardava inizialmente MSSqlServer e poi MySql è andato alla fine, quindi penso che la mia soluzione sia un po 'più flessibile in quanto sembra funzionare bene su mysql e sqlite. Non ti sei ancora preoccupato di controllare Postgres.
Questo avrebbe dovuto essere scelta come la risposta, credo che hai postato molto più tardi. –
sì, l'ho postato dopo aver visto i referral dalla risposta di Jacob. –
Si noti che se si sta utilizzando la versione 0.6 o superiore, l'istruzione import MSBinary in soluzione di Tom dovrebbe essere cambiato in "da sqlalchemy.dialects.mysql.base MSBinary importazione". Fonte: http://www.mail-archive.com/[email protected]/msg18397.html –
Vedere anche la ricetta per Backend-agnostic GUID Type nella documentazione SQLAlchemy per i tipi di colonna.
Nel caso in cui qualcuno è interessato, ho usato Tom Willis risposta, ma hanno trovato utile aggiungere una stringa alla conversione uuid.UUID nel metodo process_bind_param
class UUID(types.TypeDecorator):
impl = types.LargeBinary
def __init__(self):
self.impl.length = 16
types.TypeDecorator.__init__(self, length=self.impl.length)
def process_bind_param(self, value, dialect=None):
if value and isinstance(value, uuid.UUID):
return value.bytes
elif value and isinstance(value, basestring):
return uuid.UUID(value).bytes
elif value:
raise ValueError('value %s is not a valid uuid.UUId' % value)
else:
return None
def process_result_value(self, value, dialect=None):
if value:
return uuid.UUID(bytes=value)
else:
return None
def is_mutable(self):
return False
Ecco un approccio basato sul Backend agnostic GUID dai documenti SQLAlchemy, ma utilizzando un campo BINARY per archiviare gli UUID nei database non postgresql.
import uuid
from sqlalchemy.types import TypeDecorator, BINARY
from sqlalchemy.dialects.postgresql import UUID as psqlUUID
class UUID(TypeDecorator):
"""Platform-independent GUID type.
Uses Postgresql's UUID type, otherwise uses
BINARY(16), to store UUID.
"""
impl = BINARY
def load_dialect_impl(self, dialect):
if dialect.name == 'postgresql':
return dialect.type_descriptor(psqlUUID())
else:
return dialect.type_descriptor(BINARY(16))
def process_bind_param(self, value, dialect):
if value is None:
return value
else:
if not isinstance(value, uuid.UUID):
if isinstance(value, bytes):
value = uuid.UUID(bytes=value)
elif isinstance(value, int):
value = uuid.UUID(int=value)
elif isinstance(value, str):
value = uuid.UUID(value)
if dialect.name == 'postgresql':
return str(value)
else:
return value.bytes
def process_result_value(self, value, dialect):
if value is None:
return value
if dialect.name == 'postgresql':
return uuid.UUID(value)
else:
return uuid.UUID(bytes=value)
Quale sarebbe l'utilizzo di questo? – codeninja
Ho usato il UUIDType
dal pacchetto SQLAlchemy-Utils
: http://sqlalchemy-utils.readthedocs.org/en/latest/data_types.html#module-sqlalchemy_utils.types.uuid
Attualmente sto cercando di utilizzare questo, problema è ottengo un errore: 'alzare InvalidStatus ("notfound:. {K} (CLS = {} CLS)" formato (k = k, CLS = CLS).)' 'alchemyjsonschema.InvalidStatus: notfound: BINARIO (16). (cls =
Se si è soddisfatti con la colonna di un 'String' avere valore UUID, ecco qui una soluzione semplice:
def generate_uuid():
return str(uuid.uuid4())
class MyTable(Base):
__tablename__ = 'my_table'
uuid = Column(String, name="uuid", primary_key=True, default=generate_uuid)
Purtroppo [Tipo back-end-agnostico] (http://docs.sqlalchemy.org/en/rel_0_9/core/custom_types.html?highlight=guid#backend-agnostic-guid-type) dalla documentazione SQLAlchemy per i tipi di colonna non sembra lavorare per chiavi primarie nei motori di database SQLite. Non proprio ecumenico come speravo. – adamek