I'm using pylons and sqlalchemy and I was wondering how I could have some randoms ids as primary_key.
问题:
回答1:
the best way is to use randomly generated UUIDs:
import uuid id = uuid.uuid4()
uuid datatypes are available natively in some databases such as Postgresql (SQLAlchemy has a native PG uuid datatype for this purpose - in 0.5 its called sqlalchemy.databases.postgres.PGUuid
). You should also be able to store a uuid in any 16 byte CHAR field (though I haven't tried this specifically on MySQL or others).
回答2:
i use this pattern and it works pretty good. source
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)))
Though zzzeek I believe is the author of sqlalchemy, so if this is wrong he would know, and I would listen to him.
回答3:
Or with ORM mapping:
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)
This stores it as a string providing better database compatibility. However, you lose the database's ability to more optimally store and use the uuid.
回答4:
Years later with this problem again so I'll share my current answer. I ended up basing myself on Backend-agnostic GUID Type but I wanted to use binary instead of CHAR(32). I also wanted to deal with hex strings directly instead of UUID objects for easy printing to the user/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')
I also made a helper function to 'order' the UUID to improve indexing efficiency based on this blog post. If you're using MySQL 8 check out UUID_TO_BIN() with the swap flag and BIN_TO_UUID() instead.
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)