mysql - query - sqlalchemy selectable
ID aleatorios en sqlalchemy(pilones) (4)
Estoy usando pylons y sqlalchemy y me preguntaba cómo podría tener algunos id. De randoms como primary_key.
la mejor manera es usar UUID generados aleatoriamente:
import uuid
id = uuid.uuid4()
Los tipos de datos de uuid están disponibles de forma nativa en algunas bases de datos, como Postgresql (SQLAlchemy tiene un tipo de datos de uuid PG nativo para este fin, en 0.5 se llama sqlalchemy.databases.postgres.PGUuid
). También debería poder almacenar un uuid en cualquier campo CHAR de 16 bytes (aunque no he probado esto específicamente en MySQL u otros).
Yo uso este patrón y funciona bastante bien. fuente
from sqlalchemy import types
from sqlalchemy.databases.mysql 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)))
Aunque creo que zzzeek es el autor de sqlalchemy, entonces si esto está mal lo sabría, y yo lo escucharía.
O con el mapeo de ORM:
import uuid
from sqlalchemy import Column, Integer, String, Boolean
def uuid_gen():
return str(uuid.uuid4())
Base = declarative_base()
class Device(Base):
id = Column(String, primary_key=True, default=uuid_gen)
Esto lo almacena como una cadena que proporciona una mejor compatibilidad con la base de datos. Sin embargo, pierde la capacidad de la base de datos para almacenar y usar el uuid de manera más óptima.
Años más tarde con este problema otra vez, así que compartiré mi respuesta actual. Terminé basándome en el tipo de GUID agnóstico de Backend pero quería usar binary en lugar de CHAR (32). También quería tratar cadenas hexagonales directamente en lugar de objetos UUID para imprimir fácilmente en el usuario / url.
import binascii
import uuid
from sqlalchemy.types import TypeDecorator, BINARY
class GUID(TypeDecorator):
impl = BINARY
def load_dialect_impl(self, dialect):
return dialect.type_descriptor(BINARY(16))
def process_bind_param(self, value, dialect):
if value is None:
return value
if not isinstance(value, bytes):
if isinstance(value, uuid.UUID):
value = value.bytes
elif isinstance(value, str):
value = binascii.unhexlify(value)
else:
raise TypeError(''Invalid GUID value.'')
return value
def process_result_value(self, value, dialect):
if value is None:
return value
return binascii.hexlify(value).decode(''ascii'')
También hice una función auxiliar para ''ordenar'' el UUID para mejorar la eficiencia de indexación en base a esta publicación de blog . Si está utilizando MySQL 8, consulte UUID_TO_BIN () con el indicador de intercambio y BIN_TO_UUID () en su lugar.
def order_uuid(uuid):
uuid_str = str(uuid).replace(''-'', '''')
ordered_uuid = ''''.join([uuid_str[12:16], uuid_str[8:12], uuid_str[0:8], uuid_str[16:]])
return ordered_uuid
def revert_order_uuid(o_uuid_str):
original_uuid_str = ''''.join([o_uuid_str[8:16], o_uuid_str[4:8], o_uuid_str[0:4], o_uuid_str[16:]])
return uuid.UUID(original_uuid_str)