मैं SQLAlchemy में UUIDs का उपयोग कैसे कर सकता हूं?


95

क्या एक रास्ता (प्राथमिक कुंजी) को SQLAlchemy में UUID के रूप में परिभाषित करने का एक तरीका है यदि PostgreSQL (Postgres) का उपयोग कर रहे हैं ?


2
दुर्भाग्य से बैकएंड-अज्ञेयवादी GUID प्रकार , स्तंभ प्रकारों के लिए SQLAlchemy प्रलेखन से SQLite डेटाबेस इंजनों में प्राथमिक कुंजियों के लिए काम नहीं करता है। मैं जितना उम्मीद कर रहा था उतने इत्मिनान से नहीं।
adamek

SQLAlchemy बर्तनों UUIDType डेकोरेटर प्रदान करता है, पहिए को सुदृढ़ करने की कोई आवश्यकता नहीं है
फ़िलिप बीज़र्रा डी सूसा

जवाबों:


159

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, unique=True)

callable uuid.uuid4फ़ंक्शन को कॉल करने के बजाय कॉलम परिभाषा में पास होने से बचने के लिए सावधान रहें uuid.uuid4()। अन्यथा, आपके पास इस वर्ग के सभी उदाहरणों के लिए समान स्केलर मान होगा। अधिक जानकारी यहाँ :

इस स्तंभ के लिए डिफ़ॉल्ट मान का प्रतिनिधित्व करने वाला एक स्केलर, पाइथन कॉल करने योग्य या स्तंभकार्य अभिव्यक्ति, जिसे सम्मिलित करने पर आमंत्रित किया जाएगा यदि यह स्तंभ सम्मिलित नहीं है, तो सम्मिलित करें के मान खंड में निर्दिष्ट नहीं है।


6
मैं आपसे पूरी तरह सहमत हूं। अन्य डेटाबेस में से कुछ अन्य उत्तर शांत हैं, लेकिन पोस्टग्रेज के लिए यह सबसे साफ समाधान है। (आप एक डिफ़ॉल्ट रूप में भी सेट कर सकते हैं uuid.uuid4)।
पच

1
क्या आप एक MWE प्रदान कर सकते हैं? या शायद flask_sqlalchemy में धारावाहिक निर्माता UUID प्रकार को समझता है? पास्टबिन में त्रुटियों के नीचे कोड, pastebin.com/hW8KPuYw
ब्रैंडन दूबे

1
कोई बात नहीं, अगर आप stdlib से UUID ऑब्जेक्ट्स का उपयोग करना चाहते हैं, तोColumn(UUID(as_uuid=True) ...)
ब्रैंडन दूबे

1
धन्यवाद! यह अच्छा हो सकता है अगर Columnऔर Integerकोड स्निपेट के शीर्ष पर आयात किए गए थे, या पढ़ने के लिए बदल दिए गए थे db.Columnऔरdb.Integer
ग्रेग सैडेटस्की

2
कोई आवश्यकता नहीं है @ नीफ़नथ
फ़िलिप

65

मैंने यह लिखा था और डोमेन चला गया है लेकिन यहाँ हिम्मत है ...।

इसके बावजूद कि मेरे सहकर्मी जो वास्तव में उचित डेटाबेस डिज़ाइन के बारे में परवाह करते हैं, वे 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 बाइट्स?) की तुलना में अधिक कुशल होना चाहिए, और कुछ संकेत प्रतीत होते हैं कि 16 बाइट ब्लॉकों को अनुक्रमित करना स्ट्रिंग्स की तुलना में mysql में अधिक कुशल होना चाहिए। मैं यह वैसे भी बदतर होने की उम्मीद नहीं होगी।

एक नुकसान मैंने पाया है कि कम से कम phpymyadmin में, आप रिकॉर्ड्स को संपादित नहीं कर सकते क्योंकि यह स्पष्ट रूप से "तालिका से आईडी" = "और" विविध प्रदर्शन समस्याओं के लिए कुछ प्रकार के वर्ण रूपांतरण करने की कोशिश करता है।

इसके अलावा सब कुछ ठीक काम करने लगता है, और इसलिए मैं इसे वहां फेंक रहा हूं। एक टिप्पणी छोड़ें यदि आप इसके साथ एक गड़बड़ त्रुटि देखते हैं। मैं इसमें सुधार के लिए किसी भी सुझाव का स्वागत करता हूं।

जब तक मैं कुछ याद नहीं कर रहा हूँ उपरोक्त समाधान काम करेगा अगर अंतर्निहित डेटाबेस में UUID प्रकार है। यदि ऐसा नहीं होता है, तो तालिका बनाए जाने पर आपको संभवतः त्रुटियाँ मिलेंगी। मैं जिस समाधान के साथ आया था, मैं मूल रूप से MSSqlServer को लक्षित कर रहा था और फिर अंत में MySql चला गया, इसलिए मुझे लगता है कि मेरा समाधान थोड़ा अधिक लचीला है क्योंकि यह mysql और sqlite पर ठीक काम करता है। चेकिंग परेशान नहीं है अभी तक पोस्टग्रेट्स।


याकूब के जवाब से रेफरल देखने के बाद मैंने इसे पोस्ट किया।
टॉम विलिस

4
ध्यान दें कि यदि आप संस्करण 0.6 या अधिक का उपयोग कर रहे हैं, तो टॉम के समाधान में MSBinary आयात विवरण को "sqlalchemy.dialects.mysql.base आयात MSBinary से" में बदल दिया जाना चाहिए। स्रोत: mail-archive.com/sqlalchemy@googlegroups.com/msg18397.html
कैल जैकबसन

2
"मैंने यह लिखा है" एक मृत कड़ी है।
जुलक्स

2
यह भी देखें UUIDType कि SQLAlchemy-utils
driftcatcher

2
@codeninja postgresql में पहले से ही एक देशी UUID प्रकार है, इसलिए sqlalchemy.dialects.postgresql.UUIDसीधे उपयोग करें। देख बैकएंड-अज्ञेयवाद GUID प्रकार
cowbert

24

यदि आप UUID मान वाले 'स्ट्रिंग' कॉलम से खुश हैं, तो यहां एक सरल उपाय दिया गया है:

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

class MyTable(Base):
    __tablename__ = 'my_table'

    uuid = Column(String, name="uuid", primary_key=True, default=generate_uuid)

5
UUID को स्ट्रिंग के रूप में संग्रहीत न करें जब तक कि आप वास्तव में अजीब डेटाबेस का उपयोग नहीं कर रहे हैं जो उनका समर्थन नहीं करता है। अन्यथा, शायद अपने सभी डेटा को स्ट्रिंग्स के रूप में संग्रहीत करें ...;)
निक

@ क्यों? नकारात्मक क्या है?
18

6
@rayepps - कई डाउनसाइड हैं - मन के शीर्ष से कुछ दूर: आकार - स्ट्रिंग uuid दो बार अंतरिक्ष में ले जाता है - 16bytes बनाम 32 वर्ण - किसी भी स्वरूपक सहित नहीं। प्रसंस्करण समय - अधिक बाइट्स = सीपीयू द्वारा अधिक प्रसंस्करण समय क्योंकि आपका डेटासेट बड़ा हो जाता है। uuid स्ट्रिंग प्रारूप भाषा से भिन्न होते हैं, इसके अतिरिक्त आवश्यक अनुवाद जोड़ते हैं। किसी के लिए स्तंभ का दुरुपयोग करना आसान है, क्योंकि आप वहां कुछ भी रख सकते हैं, जो कि uuids नहीं हैं। यह शुरू करने के लिए पर्याप्त होना चाहिए।
निक

आपको प्रदर्शन के मुद्दों के लिए स्ट्रिंग्स को यूआईडी के लिए कॉलम के रूप में उपयोग नहीं करना चाहिए। एक बाइनरी (16) अधिक अनुशंसित है।
सिरिल एन।

19

मैंने पैकेज UUIDTypeसे उपयोग किया है SQLAlchemy-Utils: http://sqlalchemy-utils.readthedocs.org/en/latest/data_types.html#module-sqlalchemy_utils.types.uuid


मैं वर्तमान में इसका उपयोग करने की कोशिश कर रहा हूं, समस्या यह है कि मुझे एक त्रुटि मिलती है: raise InvalidStatus("notfound: {k}. (cls={cls})".format(k=k, cls=cls)) alchemyjsonschema.InvalidStatus: notfound: BINARY(16). (cls=<class 'sqlalchemy_utils.types.uuid.UUIDType'>)
कोडट्रूपर

क्या आप लोगों को त्रुटि मिली है NameError: name 'sqlalchemy_utils' is not defined:?
वाल्टर

1
SQLAlchemy-Utilsएक तृतीय-पक्ष पैकेज है, आपको इसे पहले स्थापित करने की आवश्यकता है:pip install sqlalchemy-utils
बेरिस्लाव लोपैक

यह जाने का तरीका है, हालांकि आपके प्रवासन को उन खातों या प्रणालियों की आवश्यकता होती है जिनके लिए UUID बनाम CHAR / BINARY मान uuids हैं।
rjurney

9

जब से आप 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)

1
PostgreSQL डेटाबेस का उपयोग करने वाले उन डेवलपर्स के लिए यह एकमात्र स्वीकृत उत्तर होना चाहिए।
जोस एल। पेटिओनो 12

6

यहां SQLAlchemy डॉक्स से बैकएंड अज्ञेयवादी GUID पर आधारित एक दृष्टिकोण है , लेकिन गैर-पोस्टग्रेजल डेटाबेस में यूयूआईडी को स्टोर करने के लिए एक बायनेरी फ़ील्ड का उपयोग करना है।

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)

1
इससे क्या फायदा होगा?
कोडट्रूपर

3

अगर किसी को दिलचस्पी है, तो मैं टॉम विलिस जवाब का उपयोग कर रहा हूं, लेकिन 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

-19

आप उदाहरण के लिए, एक कस्टम प्रकार लिखने का प्रयास कर सकते हैं :

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

फ्लोरियन के जवाब के अलावा , यह ब्लॉग प्रविष्टि भी है । यह समान दिखता है सिवाय इसके कि यह types.TypeDecoratorइसके बजाय उपवर्ग करता है types.TypeEngine। या तो दृष्टिकोण एक दूसरे पर एक फायदा या नुकसान है?
याकूब गेब्रियलसन

11
यह भी काम नहीं करता है, यह केवल डॉक्स से डमी प्रकार के उदाहरण से कट-एंड-पेस्ट काम है। टॉम विलिस का जवाब बहुत बेहतर है।
जेसी ढिल्लन

क्या इसकी जरूरत नहीं है default=?? जैसेColumn('id', UUID(), primary_key=True, default=<someautouuidgeneratingthing>)
iJames

"पृष्ठ नहीं मिला" के लिंक बिंदु, docs.sqlalchemy.org/en/13/core/… पुराने रूप से पुराने के करीब है
barbsan
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.