programing

SQLAlchemy에서 UUID를 사용하려면 어떻게 해야 합니까?

abcjava 2023. 5. 31. 14:04
반응형

SQLAlchemy에서 UUID를 사용하려면 어떻게 해야 합니까?

PostgreSQL(Postgres)을 사용하는 경우 SQLAlchemy에서 열(기본 키)을 UUID로 정의하는 방법이 있습니까?

sqlalchemy postgres 방언은 UUID 열을 지원합니다.이것은 쉽다 (그리고 질문은 구체적으로 사후적이다) -- 저는 왜 다른 답들이 모두 그렇게 복잡한지 이해할 수 없습니다.

다음은 예입니다.

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

db = SQLAlchemy()

class Foo(db.Model):
    id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)

패스하는 것을 놓치지 않도록 주의하세요.callable uuid.uuid4로, 함수 자체를 호출대자정의로신으로 보다.uuid.uuid4()그렇지 않으면 이 클래스의 모든 인스턴스에 대해 동일한 스칼라 값을 갖게 됩니다.자세한 내용은 여기:

이 열의 기본값을 나타내는 스칼라, Python 호출 가능 또는 ColumnElement 식으로, 삽입 시 이 열이 삽입의 VALUE 절에 지정되지 않은 경우 호출됩니다.

가 이것을 썼고 도메인은 사라졌지만 여기 배짱이 있습니다.

적절한 데이터베이스 설계에 관심이 많은 동료들이 키 필드에 사용되는 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)))

저는 바이너리(16바이트)로 저장하는 것이 문자열 표현(36바이트?)보다 더 효율적일 것이라고 생각합니다. 그리고 mysql에서 16바이트 블록을 인덱싱하는 것이 문자열보다 더 효율적이라는 지적도 있는 것 같습니다.저는 어쨌든 그것이 더 나빠질 것이라고 기대하지 않을 것입니다.

제가 발견한 한 가지 단점은 적어도 phpymyadmin에서 레코드를 편집할 수 없다는 것입니다. 왜냐하면 id가 =인 테이블에서 선택 *에 대해 암묵적으로 일종의 문자 변환을 시도하고 기타 표시 문제가 있기 때문입니다.

그 외에는 모든 것이 잘 작동하는 것 같아서, 저는 그것을 밖에 버리고 있습니다.명백한 오류가 발견되면 댓글을 남겨주세요.저는 그것을 개선하기 위한 어떠한 제안도 환영합니다.

기본 데이터베이스에 UUID 유형이 있으면 위의 솔루션이 작동합니다.그렇지 않으면 테이블을 만들 때 오류가 발생할 수 있습니다.제가 생각해낸 솔루션은 원래 MSSqlServer를 목표로 하다가 결국 MySql로 갔기 때문에 mysql과 sqlite에서 잘 작동하는 것 같아 제 솔루션이 조금 더 유연하다고 생각합니다.아직 우편물 확인하는 것을 귀찮아하지 않았습니다.

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)

나는 그것을 사용했습니다.UUIDType포장에서.

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)

다음은 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)

관심 있는 사람이 있으면 Tom Willis answer를 사용했지만 uuid에 문자열을 추가하는 데 유용했습니다.process_bind_param 메서드의 UUID 변환

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

동일한 문제가 발생했습니다. 이 문제가 해결될 것입니다. 저에게 적합합니다.

from sqlalchemy import Column, text
from sqlalchemy.dialects.postgresql import UUID

Column(
    "id", UUID(as_uuid=True),
    primary_key=True,
    server_default=text("gen_random_uuid()"),
)

Postgre를 사용하는 경우SQL < 14, 이 확장 팩을 추가해야 할 것 같습니다.

CREATE EXTENSION IF NOT EXISTS "pgcrypto";

사용할 수 있습니다.uuid_generate_v4()또한 다음과 같이 확장 팩을 추가해야 합니다.

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

우리는 사용할 수 있습니다.UUIDType,

from sqlalchemy_utils import UUIDType
from sqlalchemy import String

class User(Base):
    id = Column(UUIDType(binary=False), primary_key=True, default=uuid.uuid4)
    name = Column(String)

자세한 내용은 공식 문서를 참조하십시오.

SQLLchemy 2.0은 이전 Postgre와 역호환되는 데이터베이스 독립형의 SQL-네이티브 형식인 UUID 유형을 추가합니다.SQL 전용 버전의 UUID입니다.

예:

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

class Base(DeclarativeBase):
    pass

class MyModel(Base):
    my_field: Mapped[sa.UUID]

다음과 같은 사용자 지정 유형을 작성해 볼 수 있습니다.

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),
)

언급URL : https://stackoverflow.com/questions/183042/how-can-i-use-uuids-in-sqlalchemy

반응형