如何在SQLAlchemy中使用UUID?

Vas*_*sil 65 python postgresql orm uuid sqlalchemy

如果使用PostgreSQL(Postgres),有没有办法在SQLAlchemy中将列(主键)定义为UUID

JDi*_*teo 80

sqlalchemy postgres方言支持UUID列.这很容易(问题特别是postgres) - 我不明白为什么其他答案都那么复杂.

这是一个例子:

from sqlalchemy.dialects.postgresql import UUID
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Foo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    uuid = db.Column(UUID(as_uuid=True), unique=True, nullable=False)
Run Code Online (Sandbox Code Playgroud)

  • 我完全同意你的看法.其他一些答案对于其他数据库来说很酷,但对于postgres来说这是最干净的解决方案.(您也可以将默认值设置为"uuid.uuid4"). (4认同)
  • 不,没有必要@nephanth (2认同)

Tom*_*lis 62

我写了这个,域名已经消失,但这里是胆量....

无论我真正关心正确数据库设计的同事如何看待用于关键字段的UUID和GUID.我经常发现我需要这样做.我认为它比自动增量有一些优势使它值得.

在过去的几个月里,我一直在改进UUID列类型,我想我终于搞定了.

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)))
Run Code Online (Sandbox Code Playgroud)

我认为存储为二进制(16字节)最终应该比字符串表示(36字节?)更有效,并且似乎有一些迹象表明索引16字节块在mysql中应该比字符串更有效.不管怎样,我不认为它会更糟.

我发现的一个缺点是,至少在phpymyadmin中,你无法编辑记录,因为它隐式地尝试对"select*from table where id = ..."进行某种字符转换,并且存在各种显示问题.

除此之外,一切似乎都很好,所以我把它扔出去了.如果你看到一个明显的错误,请发表评论.我欢迎任何改进它的建议.

除非我遗漏了某些内容,否则如果底层数据库具有UUID类型,则上述解决方案将起作用.如果没有,则在创建表时可能会出错.我提出的解决方案是我最初的目标是MSSqlServer,最后是MySql,所以我认为我的解决方案更灵活,因为它似乎在mysql和sqlite上工作正常.还没有打扰检查postgres.

  • 请注意,如果您使用的是0.6或更高版本,则Tom解决方案中的MSBinary导入语句应更改为"from sqlalchemy.dialects.mysql.base import MSBinary".来源:http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg18397.html (4认同)
  • “我写了这个”是一个死链接。 (2认同)
  • 另请参见[SQLAlchemy-utils附带的UUIDType](http://sqlalchemy-utils.readthedocs.org/en/latest/data_types.html#module-sqlalchemy_utils.types.uuid) (2认同)
  • @codeninja postgresql已经有了一个原生的UUID类型,所以直接使用`sqlalchemy.dialects.postgresql.UUID`.参见[Backend-agnostic GUID Type](http://docs.sqlalchemy.org/en/latest/core/custom_types.html#backend-agnostic-guid-type) (2认同)

Kam*_*iel 32

另请参阅SQLAlchemy文档中有关列类型的Backend-agnostic GUID Type的配方.


小智 20

如果您对具有UUID值的"String"列感到满意,这里有一个简单的解决方案:

def generate_uuid():
    return str(uuid.uuid4())

class MyTable(Base):
    __tablename__ = 'my_table'

    uuid = Column(String, name="uuid", primary_key=True, default=generate_uuid)
Run Code Online (Sandbox Code Playgroud)

  • @rayeps - 有很多缺点 - 有一些是最重要的:大小 - 字符串 uuid 占用两倍的空间 - 16 字节 vs 32 个字符 - 不包括任何格式化程序。处理时间 - 更多字节 = 随着数据集变大,CPU 处理时间更多。uuid 字符串格式因语言而异,需要添加额外的翻译。有人更容易滥用该列,因为您可以在其中放置任何非 uuid 的内容。这应该足以开始了。 (8认同)
  • sqlite 是否有资格成为“非常奇怪的数据库”?:P (6认同)
  • 除非您使用不支持它们的非常奇怪的数据库,否则不要将UUID存储为字符串.否则,可能将所有数据存储为字符串......;) (4认同)
  • 出于性能问题,您不应使用字符串作为 uuid 的列。更推荐使用 Binary(16)。 (4认同)

con*_*gus 16

SQLAlchemy 2.0 添加了UUID 类型,这是与数据库无关的类型的 SQL 本机形式,它向后兼容以前的仅 PostgreSQL 版本的 UUID。

例子:

import sqlalchemy as sa
from sqlalchemy.orm import DeclarativeBase, Mapped

class Base(DeclarativeBase):
    pass

class MyModel(Base):
    my_field: Mapped[sa.UUID]
Run Code Online (Sandbox Code Playgroud)


Gra*_*nat 10

由于您使用的是 Postgres,因此应该可以:

from app.main import db
from sqlalchemy.dialects.postgresql import UUID

class Foo(db.Model):
    id = db.Column(UUID(as_uuid=True), primary_key=True)
    name = db.Column(db.String, nullable=False)
Run Code Online (Sandbox Code Playgroud)

  • 这是 JDiMatteo 答案的重复版本。 (2认同)

zwi*_*ier 6

这是一种基于SQLAlchemy 文档中后端不可知 GUID的方法,但使用 BINARY 字段将 UUID 存储在非 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)
Run Code Online (Sandbox Code Playgroud)


Flo*_*sch -21

您可以尝试编写自定义类型,例如:

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),
)
Run Code Online (Sandbox Code Playgroud)

  • 这甚至不起作用,这只是文档中虚拟类型示例的剪切和粘贴工作。汤姆威利斯下面的回答要好得多。 (11认同)