Django मॉडल (सामान्य संबंध प्रभाव) में प्राथमिक कुंजी के रूप में एक UUID का उपयोग करना


90

कई कारणों से ^, मैं अपने कुछ Django मॉडल में एक प्राथमिक कुंजी के रूप में एक UUID का उपयोग करना चाहूंगा। यदि मैं ऐसा करता हूं, तो क्या मैं अब भी "कंट्रीबॉटमेंट्स", "डीजेंगो-वोटिंग" या "डीजेंगो-टैगिंग" जैसे बाहरी ऐप का उपयोग कर पाऊंगा जो कंटेंट टाइप के माध्यम से सामान्य संबंधों का उपयोग करते हैं?

एक उदाहरण के रूप में "django- मतदान" का उपयोग करना, वोट मॉडल इस तरह दिखता है:

class Vote(models.Model):
    user         = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id    = models.PositiveIntegerField()
    object       = generic.GenericForeignKey('content_type', 'object_id')
    vote         = models.SmallIntegerField(choices=SCORES)

यह ऐप यह मान रहा है कि जिस मॉडल को वोट दिया जा रहा है उसके लिए प्राथमिक कुंजी पूर्णांक है।

बिल्ट-इन कमेंट्स ऐप गैर-पूर्णांक पीके को संभालने में सक्षम प्रतीत होता है, हालाँकि:

class BaseCommentAbstractModel(models.Model):
    content_type   = models.ForeignKey(ContentType,
            verbose_name=_('content type'),
            related_name="content_type_set_for_%(class)s")
    object_pk      = models.TextField(_('object ID'))
    content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")

क्या यह "पूर्णांक-पीके-मान लिया गया" समस्या तृतीय-पक्ष एप्लिकेशन के लिए एक सामान्य स्थिति है जो यूयूआईडी का उपयोग करके दर्द का कारण बनेगी? या, संभवतः, क्या मैं इस स्थिति को गलत बता रहा हूं?

वहाँ बहुत परेशानी का कारण के बिना Django में प्राथमिक कुंजी के रूप में UUIDs का उपयोग करने का एक तरीका है?


^ कारणों में से कुछ: छिपाना वस्तु मायने रखता है, url "आईडी क्रॉलिंग" को रोकना, गैर-संघर्षशील वस्तुओं को बनाने के लिए कई सर्वरों का उपयोग करना, ...

जवाबों:


55

एक यूयूआईडी प्राथमिक कुंजी न केवल सामान्य संबंधों के साथ, बल्कि सामान्य रूप से दक्षता के साथ समस्याओं का कारण बनेगी: प्रत्येक विदेशी कुंजी काफी महंगी होगी - दोनों को स्टोर करने के लिए, और मशीन शब्द की तुलना में जुड़ने के लिए।

हालाँकि, UUID को प्राथमिक कुंजी के लिए कुछ भी करने की आवश्यकता नहीं है: बस इसके साथ एक uu क्षेत्र के साथ अपने मॉडल को पूरक करके इसे एक माध्यमिक कुंजी बनाएं unique=True। अंतर्निहित प्राथमिक कुंजी को सामान्य (अपने सिस्टम के लिए आंतरिक) के रूप में उपयोग करें, और अपने बाहरी पहचानकर्ता के रूप में UUID का उपयोग करें।


16
जो होलोवे, इसके लिए कोई ज़रूरत नहीं है: आप बस क्षेत्र के रूप में यूयूआईडी पीढ़ी समारोह की आपूर्ति कर सकते हैं default
Pi Delport

4
जो: मैं अपने मॉडल में अपने यूयूआईडी बनाने के लिए django_extensions.db.fields.UUIDField का उपयोग करता हूं। यह सरल है, मैं सिर्फ अपने क्षेत्र को इस तरह परिभाषित करता हूं: user_uuid = UUIDField ()
मिचफ

3
django_extensions.db.fields.UUIDField@MatthewSchinckel : जब आप मिचफ द्वारा बताए अनुसार उपयोग करते हैं , तो आपको Django-South के माइग्रेशन के साथ कोई समस्या नहीं होगी - उनके द्वारा उल्लेखित फ़ील्ड ने दक्षिण माइग्रेशन के लिए अंतर्निहित समर्थन दिया है।
टाडेक

125
भयानक जवाब। पोस्टग्रैज में देशी (128 बिट) यूयूआईडी हैं जो 64 बिट मशीन पर केवल 2 शब्द हैं, इसलिए देशी 64 बिट आईएनटी की तुलना में "काफी महंगा" नहीं होगा।
Postfuturist

8
पीट, यह देखते हुए कि इस पर एक btree सूचकांक है, किसी दिए गए क्वेरी पर कितनी तुलनाएं होने जा रही हैं? ज्यादा नहीं। इसके अलावा, मुझे यकीन है कि मेमकैंप कॉल को अधिकांश ओएस पर संरेखित और अनुकूलित किया जाएगा। सवालों की प्रकृति के आधार पर, मैं कहूंगा कि नहीं UUID का उपयोग कर, क्योंकि संभव (संभावना नगण्य) प्रदर्शन मतभेद की गलत अनुकूलन है।
पोस्टफुटुरिस्ट

219

जैसा कि प्रलेखन में देखा गया है , Django 1.8 से UUID फ़ील्ड में बनाया गया है। UUID बनाम पूर्णांक का उपयोग करते समय प्रदर्शन अंतर नगण्य हैं।

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

अधिक जानकारी के लिए आप इस उत्तर को भी देख सकते हैं ।


@Keithhackbarth कैसे हम django को हर बार तालिका के लिए आईडी बनाते समय इसका उपयोग करने के लिए सेट करते हैं?
२०:५० पर anon58192932

3
@ anon58192932 वास्तव में स्पष्ट नहीं है कि वास्तव में "हर बार" से आपका क्या मतलब है। यदि आप चाहते हैं कि UUIDs का उपयोग प्रत्येक मॉडल के लिए किया जाए, तो अपना सार आधार मॉडल बनाएं और django.models.Model के बजाय इसका उपयोग करें।
Назар Топольський

4
अंतर्निहित डेटाबेस UUID प्रकार का समर्थन करने पर प्रदर्शन अंतर केवल नगण्य हैं। Django अभी भी अधिकांश DBs के लिए एक charfield का उपयोग करता है (पोस्टग्रैस्कल केवल UUID फ़ील्ड का समर्थन करने के लिए db है)।
NirIzr

मैं उलझन में हूं कि यह एक लोकप्रिय जवाब क्यों है ... सवाल थर्ड पार्टी पैकेज के साथ कठिनाई के बारे में पूछ रहा था। Django के मूल रूप से UUID का समर्थन करने के बावजूद, अभी भी कई पैकेज प्रतीत होते हैं, जो UUID के लिए जिम्मेदार नहीं हैं। मेरे अनुभव में, यह एक दर्द है।
ambe5960

12

मैं एक समान स्थिति में भाग गया और आधिकारिक Django प्रलेखन में पता चला , कि संबंधित मॉडल object_idके प्राथमिक_की तरह एक ही प्रकार का नहीं होना चाहिए । उदाहरण के लिए, यदि आप चाहते हैं कि आपका जेनेरिक संबंध IntegerField और CharField id दोनों के लिए मान्य हो , तो बस आपको object_idएक CharField होना चाहिए । के बाद से पूर्णांक तार में मोटे हो सकते हैं यह ठीक हो जाएगा। वही UUIDField के लिए जाता है ।

उदाहरण:

class Vote(models.Model):
    user         = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id    = models.CharField(max_length=50) # <<-- This line was modified 
    object       = generic.GenericForeignKey('content_type', 'object_id')
    vote         = models.SmallIntegerField(choices=SCORES)

3

UUID के साथ PK के रूप में असली समस्या डिस्क के विखंडन और गैर-संख्यात्मक पहचानकर्ताओं के साथ जुड़े गिरावट को सम्मिलित करना है। क्योंकि पीके एक क्लस्टर इंडेक्स है, जब यह ऑटो-इन्क्रीमेंट नहीं होता है, तो आपके डीबी इंजन को कम ऑर्डिनैलिटी की आईडी के साथ एक पंक्ति सम्मिलित करते समय आपके भौतिक ड्राइव का सहारा लेना होगा, जो कि यूयूआईडी के साथ हर समय होगा। जब आपको अपने DB में बहुत सारे डेटा मिलते हैं, तो एक नया रिकॉर्ड डालने में कई सेकंड या मिनट भी लग सकते हैं। और आपकी डिस्क अंततः खंडित हो जाएगी, आवधिक डिस्क डीफ़्रेग्मेंटेशन की आवश्यकता होगी। यह सब वास्तव में बुरा है।

इन्हें हल करने के लिए, मैं हाल ही में निम्नलिखित वास्तुकला के साथ आया था जो मुझे लगा कि साझा करने के लायक होगा।

UUID छद्म-प्राथमिक-कुंजी

यह विधि आपको प्राथमिक कुंजी के रूप में एक यूयूआईडी के लाभों का लाभ उठाने की अनुमति देती है (एक अद्वितीय सूचकांक यूयूआईडी का उपयोग करते हुए), जबकि विखंडन को संबोधित करने और गैर-संख्यात्मक पीके होने के प्रदर्शन डीग्रेशन चिंताओं को सम्मिलित करने के लिए एक ऑटो-इंक्रीमेंट किए गए पीके को बनाए रखना।

यह काम किस प्रकार करता है:

  1. pkidअपने DB मॉडल पर कॉल की गई ऑटो-इन्क्रिमेटेड प्राथमिक कुंजी बनाएँ ।
  2. idएक संख्यात्मक प्राथमिक कुंजी के बजाय एक UUID आईडी द्वारा आपको खोजने के लिए एक अद्वितीय अनुक्रमित UUID फ़ील्ड जोड़ें ।
  3. फॉरेनकेय को यूयूआईडी की ओर इंगित करें (उपयोग करते हुए to_field='id') अपने विदेशी-कुंजी को संख्यात्मक आईडी के बजाय छद्म-पीके का प्रतिनिधित्व करने के लिए अनुमति दें।

अनिवार्य रूप से, आप निम्न कार्य करेंगे:

सबसे पहले, एक सार Django बेस मॉडल बनाएं

class UUIDModel(models.Model):
    pkid = models.BigAutoField(primary_key=True, editable=False)
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)

    class Meta:
        abstract = True

मॉडल के बजाय बेस मॉडल का विस्तार करना सुनिश्चित करें। मोडेल

class Site(UUIDModel):
    name = models.CharField(max_length=255)

यह भी सुनिश्चित करें कि आपके विदेशियों idको ऑटो- इन्क्रिएटेड फ़ील्ड के बजाय UUID फ़ील्ड पर इंगित करें pkid:

class Page(UUIDModel):
    site = models.ForeignKey(Site, to_field='id', on_delete=models.CASCADE)

यदि आप Django रेस्ट फ्रेमवर्क (DRF) का उपयोग कर रहे हैं, तो डिफ़ॉल्ट खोज फ़ील्ड सेट करने के लिए बेस व्यूसेट क्लास भी बनाना सुनिश्चित करें:

class UUIDModelViewSet(viewsets.ModelViewSet):
    lookup_field = 'id' 

और अपने API विचारों के लिए आधार के बजाय ModelViewSet का विस्तार करें:

class SiteViewSet(UUIDModelViewSet):
    model = Site

class PageViewSet(UUIDModelViewSet):
    model = Page

इस लेख में क्यों और कैसे पर अधिक नोट्स: https://www.stevenmoseley.com/blog/uuid-primary-keys-django-rest-framework-2-steps


0

यह निम्नलिखित चरणों का उपयोग करके एक कस्टम बेस अमूर्त मॉडल का उपयोग करके किया जा सकता है।

पहले अपने प्रोजेक्ट में एक फोल्डर बनाएं, इसे बेसमॉडल कहें, फिर नीचे दिए गए के साथ एक एब्स्ट्रॉमोडेलबेसक्रेड को जोड़ें:

from django.db import models
import uuid


class BaseAbstractModel(models.Model):

    """
     This model defines base models that implements common fields like:
     created_at
     updated_at
     is_deleted
    """
    id=models.UUIDField(primary_key=True, ,unique=True,default=uuid.uuid4, editable=False)
    created_at=models.DateTimeField(auto_now_add=True,editable=False)
    updated_at=models.DateTimeField(auto_now=True,editable=False)
    is_deleted=models.BooleanField(default=False)

    def soft_delete(self):
        """soft  delete a model instance"""
        self.is_deleted=True
        self.save()

    class Meta:
        abstract=True
        ordering=['-created_at']

दूसरा: प्रत्येक एप्लिकेशन के लिए आपकी सभी मॉडल फ़ाइल में ऐसा करें

from django.db import models
from basemodel import BaseAbstractModel
import uuid

# Create your models here.

class Incident(BaseAbstractModel):

    """ Incident model  """

    place = models.CharField(max_length=50,blank=False, null=False)
    personal_number = models.CharField(max_length=12,blank=False, null=False)
    description = models.TextField(max_length=500,blank=False, null=False)
    action = models.TextField(max_length=500,blank=True, null=True)
    image = models.ImageField(upload_to='images/',blank=True, null=True)
    incident_date=models.DateTimeField(blank=False, null=False) 

तो उपरोक्त मॉडल घटना ने आधारभूत मॉडल में सभी क्षेत्र को निहित किया है।


-1

इस सवाल को फिर से परिभाषित किया जा सकता है कि "क्या ऑटो-इंक्रीमेंट किए गए पूर्णांक के बजाय सभी डेटाबेस आईडी में सभी डेटाबेस आईडी के लिए यूएओआईडी का उपयोग करने का एक तरीका है?"

ज़रूर, मैं कर सकता हूँ:

id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

मेरी सभी तालिकाओं में, लेकिन मुझे इसके लिए ऐसा करने का तरीका नहीं मिला:

  1. 3 पार्टी मॉड्यूल
  2. Django ने कईToMany तालिकाओं का निर्माण किया

तो, यह एक लापता Django सुविधा प्रतीत होती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.