Django 2.1 - Multiple databases

एकाधिक डेटाबेस




django

एकाधिक डेटाबेस

यह विषय गाइड कई डेटाबेस के साथ बातचीत के लिए Django के समर्थन का वर्णन करता है। Django के बाकी डॉक्यूमेंट्स में से अधिकांश आप एक ही डेटाबेस के साथ बातचीत कर रहे हैं। यदि आप कई डेटाबेस के साथ बातचीत करना चाहते हैं, तो आपको कुछ अतिरिक्त कदम उठाने होंगे।

यह भी देखें

कई डेटाबेस के साथ परीक्षण के बारे में जानकारी के लिए मल्टी-डेटाबेस समर्थन देखें।

अपने डेटाबेस को परिभाषित करना

Django के साथ एक से अधिक डेटाबेस का उपयोग करने का पहला कदम Django को उन डेटाबेस सर्वरों के बारे में बताना है जिन्हें आप उपयोग कर रहे हैं। यह DATABASES सेटिंग का उपयोग करके किया जाता है। यह सेटिंग डेटाबेस उपनामों को दर्शाता है, जो कि उस विशिष्ट कनेक्शन के लिए सेटिंग्स के शब्दकोश में, Django में एक विशिष्ट डेटाबेस को संदर्भित करने का एक तरीका है। आंतरिक शब्दकोशों में सेटिंग्स को पूरी तरह से DATABASES प्रलेखन में वर्णित किया गया है।

डेटाबेस में आपके द्वारा चुना गया कोई भी अन्य नाम हो सकता है। हालांकि, उपनाम default का विशेष महत्व है। Django default से उपनाम के साथ डेटाबेस का उपयोग करता है जब कोई अन्य डेटाबेस नहीं चुना गया है।

निम्नलिखित एक उदाहरण settings.py दो डेटाबेसों को परिभाषित करने वाला स्निपेट - एक डिफ़ॉल्ट पोस्टग्रैसक्यूएल डेटाबेस और एक माईएसक्यूएल डेटाबेस जिसे users कहते users :

DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}

यदि default डेटाबेस की अवधारणा आपके प्रोजेक्ट के संदर्भ में कोई मतलब नहीं रखती है, तो आपको उस डेटाबेस को हमेशा निर्दिष्ट करने के लिए सावधान रहने की आवश्यकता है जिसे आप उपयोग करना चाहते हैं। Django के लिए आवश्यक है कि एक default डेटाबेस प्रविष्टि को परिभाषित किया जाए, लेकिन इसका उपयोग नहीं किया जाएगा तो पैरामीटर शब्दकोश को खाली छोड़ दिया जा सकता है। ऐसा करने के लिए, आपको अपने ऐप्स के सभी मॉडलों के लिए DATABASE_ROUTERS सेट करना होगा, जिनमें आपके द्वारा उपयोग किए जा रहे किसी भी कंट्रास्ट और तृतीय-पक्ष ऐप में शामिल हैं, ताकि कोई भी डिफॉल्ट डेटाबेस में कोई प्रश्न न आए। निम्नलिखित एक उदाहरण settings.py दो गैर-डिफ़ॉल्ट डेटाबेस को परिभाषित करने वाला स्निपेट, default प्रविष्टि जानबूझकर खाली छोड़ दिया गया है:

DATABASES = {
    'default': {},
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'superS3cret'
    },
    'customers': {
        'NAME': 'customer_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_cust',
        'PASSWORD': '[email protected]'
    }
}

यदि आप किसी डेटाबेस को अपने DATABASES सेटिंग में परिभाषित नहीं करने का प्रयास करते हैं, तो Django एक django.db.utils.ConnectionDoesNotExist अपवाद django.db.utils.ConnectionDoesNotExist

अपने डेटाबेस को सिंक्रनाइज़ करना

migrate प्रबंधन कमांड एक समय में एक डेटाबेस पर काम करता है। डिफ़ॉल्ट रूप से, यह default डेटाबेस पर काम करता है, लेकिन --database विकल्प प्रदान करके, आप इसे किसी भिन्न डेटाबेस को सिंक्रनाइज़ करने के लिए कह सकते हैं। इसलिए, ऊपर दिए गए पहले उदाहरण में सभी डेटाबेस पर सभी मॉडलों को सिंक्रनाइज़ करने के लिए, आपको कॉल करना होगा:

$ ./manage.py migrate
$ ./manage.py migrate --database=users

यदि आप नहीं चाहते कि प्रत्येक एप्लिकेशन किसी विशेष डेटाबेस पर सिंक्रनाइज़ हो, तो आप एक डेटाबेस राउटर को परिभाषित कर सकते हैं जो किसी विशेष मॉडल की उपलब्धता को बाधित करने वाली नीति को लागू करता है।

यदि, ऊपर दिए गए दूसरे उदाहरण के अनुसार, आपने default डेटाबेस को खाली छोड़ दिया है, तो आपको migrate चलाने के migrate हर बार एक डेटाबेस नाम प्रदान करना होगा। डेटाबेस नाम को छोड़ते समय एक त्रुटि होगी। दूसरे उदाहरण के लिए:

$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers

अन्य प्रबंधन आदेशों का उपयोग करना

अधिकांश अन्य django-admin कमांड्स जो डेटाबेस के साथ इंटरैक्ट करते हैं, उसी तरह से काम करते हैं जैसे कि वे migrate - वे केवल एक समय में एक डेटाबेस पर काम करते हैं, --database का उपयोग --database गए डेटाबेस को नियंत्रित करने के लिए करते हैं।

इस नियम का अपवाद makemigrations कमांड है। यह नए माइग्रेशन बनाने से पहले मौजूदा माइग्रेशन फ़ाइलों (जो उन्हें संपादित करने के कारण हो सकता है) के साथ समस्याओं को पकड़ने के लिए डेटाबेस में माइग्रेशन इतिहास को मान्य करता है। डिफ़ॉल्ट रूप से, यह केवल default डेटाबेस की जांच करता है, लेकिन यह किसी भी स्थापित होने पर राउटर के allow_migrate() विधि को allow_migrate() है।

स्वचालित डेटाबेस रूटिंग

कई डेटाबेस का उपयोग करने का सबसे आसान तरीका एक डेटाबेस रूटिंग योजना स्थापित करना है। डिफ़ॉल्ट रूटिंग योजना यह सुनिश्चित करती है कि वस्तुएं अपने मूल डेटाबेस से 'चिपकी रहें' (अर्थात, foo डेटाबेस से प्राप्त वस्तु को उसी डेटाबेस में सहेजा जाएगा)। डिफ़ॉल्ट रूटिंग योजना यह सुनिश्चित करती है कि यदि कोई डेटाबेस निर्दिष्ट नहीं है, तो सभी क्वेरीज़ default डेटाबेस पर वापस आती हैं।

आपको डिफ़ॉल्ट रूटिंग योजना को सक्रिय करने के लिए कुछ भी करने की ज़रूरत नहीं है - यह हर Django परियोजना पर 'आउट ऑफ द बॉक्स' प्रदान की जाती है। हालांकि, यदि आप अधिक दिलचस्प डेटाबेस आवंटन व्यवहारों को लागू करना चाहते हैं, तो आप अपने स्वयं के डेटाबेस राउटर्स को परिभाषित और स्थापित कर सकते हैं।

डेटाबेस राउटर

डेटाबेस राउटर एक ऐसा वर्ग है जो अधिकतम चार तरीके प्रदान करता है:

db_for_read(model, **hints)

उस डेटाबेस का सुझाव दें जिसका उपयोग टाइप model की वस्तुओं के पढ़ने के लिए किया जाना चाहिए।

यदि कोई डेटाबेस ऑपरेशन कोई अतिरिक्त जानकारी प्रदान करने में सक्षम है जो डेटाबेस का चयन करने में सहायता कर सकता है, तो यह hints शब्दकोश में प्रदान किया जाएगा। मान्य संकेत पर विवरण below

यदि कोई सुझाव None तो None लौटाता है।

db_for_write(model, **hints)

उस डेटाबेस का सुझाव दें जिसका उपयोग टाइप मॉडल की वस्तुओं के लेखन के लिए किया जाना चाहिए।

यदि कोई डेटाबेस ऑपरेशन कोई अतिरिक्त जानकारी प्रदान करने में सक्षम है जो डेटाबेस का चयन करने में सहायता कर सकता है, तो यह hints शब्दकोश में प्रदान किया जाएगा। मान्य संकेत पर विवरण below

यदि कोई सुझाव None तो None लौटाता है।

allow_relation(obj1, obj2, **hints)

True लौटें अगर obj1 और obj2 बीच एक संबंध की अनुमति दी जानी चाहिए, तो False यदि संबंध को रोका जाना चाहिए, या None अगर राउटर की कोई राय नहीं है। यह विशुद्ध रूप से एक सत्यापन ऑपरेशन है, जिसका उपयोग विदेशी कुंजी और कई ऑपरेशनों द्वारा यह निर्धारित करने के लिए किया जाता है कि दो वस्तुओं के बीच एक संबंध की अनुमति दी जानी चाहिए।

यदि किसी राउटर की एक राय नहीं है (यानी सभी राउटर None लौटाते हैं), केवल उसी डेटाबेस के भीतर संबंधों की अनुमति है।

allow_migrate(db, app_label, model_name=None, **hints)

यह निर्धारित करें कि क्या माइग्रेशन ऑपरेशन को अलियास db साथ डेटाबेस पर चलने की अनुमति है। यदि ऑपरेशन चलाना चाहिए तो True लौटें, यदि यह नहीं चलना चाहिए, तो False , या यदि राउटर की कोई राय None तो कोई भी नहीं।

app_label स्थिति तर्क एप्लिकेशन के माइग्रेट होने का लेबल है।

model_name अधिकांश माइग्रेशन परिचालनों द्वारा मॉडल के मान के लिए सेट किया जाता है। मॉडल __name__ (मॉडल का __name__ संस्करण __name__ ) माइग्रेट किया जा रहा है। जब तक वे संकेत का उपयोग करके इसे प्रदान नहीं करते तब तक इसका मूल्य RunPython और RunSQL संचालन के लिए नहीं है।

राउटर के लिए अतिरिक्त जानकारी को संप्रेषित करने के लिए कुछ परिचालन द्वारा hints का उपयोग किया जाता है।

जब model_name सेट किया जाता है, तो hints सामान्य रूप से कुंजी 'model' तहत मॉडल वर्ग में होते हैं। ध्यान दें कि यह एक ऐतिहासिक मॉडल हो सकता है, और इस प्रकार कोई भी कस्टम विशेषताएँ, विधियाँ, या प्रबंधक नहीं हैं। आपको केवल _meta पर निर्भर रहना चाहिए।

इस पद्धति का उपयोग किसी दिए गए डेटाबेस पर मॉडल की उपलब्धता को निर्धारित करने के लिए भी किया जा सकता है।

makemigrations हमेशा मॉडल परिवर्तनों के लिए माइग्रेशन बनाता है, लेकिन अगर allow_migrate() False रिटर्न देता है, तो db पर migrate चलाने पर model_name लिए कोई भी माइग्रेशन ऑपरेशन चुपचाप छोड़ दिया जाएगा। पहले से ही माइग्रेशन वाले मॉडल के लिए allow_migrate() के व्यवहार को बदलने के परिणामस्वरूप टूटी हुई विदेशी कुंजियाँ, अतिरिक्त टेबल या लापता टेबल हो सकते हैं। जब makemigrations माइग्रेशन इतिहास की पुष्टि करता है, तो यह उन डेटाबेसों को छोड़ देता है जहां किसी भी ऐप को माइग्रेट करने की अनुमति नहीं है।

एक राउटर को इन सभी तरीकों को प्रदान करने की आवश्यकता नहीं है - यह उनमें से एक या अधिक को छोड़ सकता है। यदि विधियों में से एक को छोड़ दिया जाता है, तो प्रासंगिक जांच करते समय Django उस राउटर को छोड़ देगा।

संकेत

डेटाबेस राउटर द्वारा प्राप्त संकेत का उपयोग यह तय करने के लिए किया जा सकता है कि किस डेटाबेस को दिए गए अनुरोध को प्राप्त करना चाहिए।

वर्तमान में, एकमात्र संकेत जो प्रदान किया जाएगा, instance , एक वस्तु उदाहरण है जो पढ़ने या लिखने के संचालन से संबंधित है जो चल रहा है। यह वह उदाहरण हो सकता है जिसे सहेजा जा रहा है, या यह एक उदाहरण हो सकता है जिसे कई-से-कई संबंधों में जोड़ा जा रहा है। कुछ मामलों में, कोई उदाहरण संकेत उपलब्ध नहीं कराया जाएगा। राउटर एक संकेत संकेत के अस्तित्व की जांच करता है, और यह निर्धारित करता है कि रूटिंग व्यवहार को बदलने के लिए उस संकेत का उपयोग किया जाना चाहिए।

राउटर का उपयोग करना

डेटाबेस राउटर DATABASE_ROUTERS सेटिंग का उपयोग करके इंस्टॉल किए जाते हैं। यह सेटिंग क्लास नामों की एक सूची को परिभाषित करती है, प्रत्येक राउटर को मास्टर राउटर ( django.db.router ) द्वारा निर्दिष्ट किया जाना चाहिए।

मास्टर राउटर का उपयोग Django के डेटाबेस संचालन द्वारा डेटाबेस उपयोग को आवंटित करने के लिए किया जाता है। जब भी किसी क्वेरी को जानना होता है कि किस डेटाबेस का उपयोग करना है, तो यह मास्टर राउटर को कॉल करता है, एक मॉडल और एक संकेत प्रदान करता है (यदि उपलब्ध हो)। Django तब प्रत्येक राउटर को बदले में तब तक आज़माता है जब तक कि एक डेटाबेस सुझाव नहीं मिलता है। यदि कोई सुझाव नहीं मिल सकता है, तो यह संकेत के वर्तमान _state.db को _state.db करता है। यदि एक संकेत उदाहरण प्रदान नहीं किया गया था, या उदाहरण में वर्तमान में डेटाबेस स्थिति नहीं है, तो मास्टर राउटर default डेटाबेस को आवंटित करेगा।

एक उदाहरण

केवल उदाहरण के लिए!

यह उदाहरण राउटर के बुनियादी ढांचे के डेटाबेस के उपयोग को बदलने के लिए कैसे उपयोग किया जा सकता है, के प्रदर्शन के रूप में अभिप्रेत है। यह जानबूझकर कुछ जटिल मुद्दों की अनदेखी करता है कि कैसे राउटर्स का उपयोग किया जाता है।

यह उदाहरण काम नहीं करेगा यदि किसी भी myapp में किसी मॉडल में other डेटाबेस के बाहर के मॉडल से संबंध हैं। क्रॉस-डेटाबेस रिश्ते रेफरल अखंडता समस्याओं को पेश करते हैं जो कि Django वर्तमान में नहीं संभाल सकता है।

वर्णित प्राथमिक / प्रतिकृति (कुछ डेटाबेस द्वारा मास्टर / दास के रूप में संदर्भित) विन्यास भी त्रुटिपूर्ण है - यह प्रतिकृति अंतराल से निपटने के लिए कोई समाधान प्रदान नहीं करता है (यानी, प्रश्न के प्रचार के लिए लिखे गए समय के कारण शुरू की गई क्वेरी असंगतताएं। प्रतिकृतियां)। यह डेटाबेस उपयोग रणनीति के साथ लेनदेन की बातचीत पर भी विचार नहीं करता है।

तो - व्यवहार में इसका क्या मतलब है? आइए एक और नमूना विन्यास पर विचार करें। यह एक कई डेटाबेस होगा: एक के लिए एक अनुप्रयोग, और दो अन्य सभी एप्लिकेशन के साथ एक प्राथमिक / प्रतिकृति सेटअप का उपयोग करते हुए। यहां इन डेटाबेस को निर्दिष्ट करने वाली सेटिंग दी गई है:

DATABASES = {
    'default': {},
    'auth_db': {
        'NAME': 'auth_db',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'swordfish',
    },
    'primary': {
        'NAME': 'primary',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'spam',
    },
    'replica1': {
        'NAME': 'replica1',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'eggs',
    },
    'replica2': {
        'NAME': 'replica2',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'bacon',
    },
}

अब हमें रूटिंग को संभालने की आवश्यकता होगी। सबसे पहले हम एक राउटर चाहते हैं जो auth_db लिए auth_db ऐप के लिए प्रश्न भेजना जानता है:

class AuthRouter:
    """
    A router to control all database operations on models in the
    auth application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth_db.
        """
        if model._meta.app_label == 'auth':
            return 'auth_db'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth models go to auth_db.
        """
        if model._meta.app_label == 'auth':
            return 'auth_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth app is involved.
        """
        if obj1._meta.app_label == 'auth' or \
           obj2._meta.app_label == 'auth':
           return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth app only appears in the 'auth_db'
        database.
        """
        if app_label == 'auth':
            return db == 'auth_db'
        return None

और हम ऐसा राउटर भी चाहते हैं जो अन्य सभी ऐप्स को प्राइमरी / रेप्लिका कॉन्फ़िगरेशन में भेजता है, और बेतरतीब ढंग से पढ़ने के लिए एक प्रतिकृति चुनता है:

import random

class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return random.choice(['replica1', 'replica2'])

    def db_for_write(self, model, **hints):
        """
        Writes always go to primary.
        """
        return 'primary'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

अंत में, सेटिंग्स फ़ाइल में, हम निम्नलिखित जोड़ते हैं (पथ का प्रतिस्थापन path.to. रहे हैं। वास्तविक पायथन पथ के साथ मॉड्यूल (रों) जहां राउटर्स को परिभाषित किया गया है):

DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']

जिस क्रम में राउटर को संसाधित किया जाता है वह महत्वपूर्ण है। राउटर्स को DATABASE_ROUTERS सेटिंग में सूचीबद्ध क्रम में क्वेर किया जाएगा। इस उदाहरण में, AuthRouter को AuthRouter से पहले संसाधित किया PrimaryReplicaRouter , और परिणामस्वरूप, किसी भी अन्य निर्णय के पहले ही मॉडल के विषय में निर्णय संसाधित किए जाते हैं। यदि DATABASE_ROUTERS सेटिंग ने दूसरे क्रम में दो राउटर सूचीबद्ध किए हैं, तो PrimaryReplicaRouter.allow_migrate() को पहले संसाधित किया जाएगा। PrimaryReplicaRouter कार्यान्वयन की पकड़-सभी प्रकृति का मतलब होगा कि सभी मॉडल सभी डेटाबेस पर उपलब्ध होंगे।

इस सेटअप के साथ, कुछ Django कोड चलाने की सुविधा देता है:

>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username='fred')
>>> fred.first_name = 'Frederick'

>>> # This save will also be directed to 'auth_db'
>>> fred.save()

>>> # These retrieval will be randomly allocated to a replica database
>>> dna = Person.objects.get(name='Douglas Adams')

>>> # A new object has no database allocation when created
>>> mh = Book(title='Mostly Harmless')

>>> # This assignment will consult the router, and set mh onto
>>> # the same database as the author object
>>> mh.author = dna

>>> # This save will force the 'mh' instance onto the primary database...
>>> mh.save()

>>> # ... but if we re-retrieve the object, it will come back on a replica
>>> mh = Book.objects.get(title='Mostly Harmless')

इस उदाहरण ने राउटर को दूसरे ऐप के मॉडल के साथ इंटरैक्शन को संभालने के लिए और अन्य राउटरों को अन्य सभी ऐप के साथ बातचीत को संभालने के लिए परिभाषित किया है। यदि आपने अपना default डेटाबेस खाली छोड़ दिया है और सभी ऐप्स को अन्यथा निर्दिष्ट नहीं करने के लिए पकड़ने के लिए सभी डेटाबेस राउटर को परिभाषित नहीं करना चाहते हैं, तो आपके राउटर को माइग्रेट करने से पहले INSTALLED_APPS में सभी ऐप्स के नाम को संभालना होगा। उन कॉन्ट्रिब ऐप्स के बारे में जानकारी के लिए कंट्राब ऐप का व्यवहार देखें जो एक डेटाबेस में एक साथ होने चाहिए।

मैन्युअल रूप से एक डेटाबेस का चयन

Django भी एक एपीआई प्रदान करता है जो आपको अपने कोड में डेटाबेस उपयोग पर पूर्ण नियंत्रण बनाए रखने की अनुमति देता है। एक मैन्युअल रूप से निर्दिष्ट डेटाबेस आवंटन एक राउटर द्वारा आवंटित डेटाबेस पर प्राथमिकता देगा।

मैन्युअल रूप से QuerySet लिए डेटाबेस का चयन QuerySet

आप QuerySet "चेन" के किसी भी बिंदु पर एक QuerySet लिए डेटाबेस का चयन कर सकते हैं। निर्दिष्ट डेटाबेस का उपयोग करने वाले किसी अन्य QuerySet को प्राप्त करने के लिए QuerySet पर बस using() कॉल करें।

using() एकल तर्क लेता है: डेटाबेस का उपनाम जिस पर आप क्वेरी चलाना चाहते हैं। उदाहरण के लिए:

>>> # This will run on the 'default' database.
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using('default').all()

>>> # This will run on the 'other' database.
>>> Author.objects.using('other').all()

save() लिए एक डेटाबेस का चयन save()

किस डेटाबेस को डेटा सहेजा जाना चाहिए यह निर्दिष्ट करने के लिए Model.save() using कीवर्ड का using करें।

उदाहरण के लिए, किसी ऑब्जेक्ट को legacy_users डेटाबेस में legacy_users , आप इसका उपयोग करेंगे:

>>> my_object.save(using='legacy_users')

यदि आप using करना निर्दिष्ट नहीं using , तो राउटर द्वारा आवंटित डिफ़ॉल्ट डेटाबेस में save() विधि बच जाएगी।

किसी ऑब्जेक्ट को एक डेटाबेस से दूसरे में ले जाना

यदि आपने एक डेटाबेस में एक इंस्टेंस को सेव किया है, तो इंस्टेंस को नए डेटाबेस में माइग्रेट करने के तरीके के रूप में save(using=...) उपयोग करने के लिए लुभावना हो सकता है। हालाँकि, यदि आप उचित कदम नहीं उठाते हैं, तो इसके कुछ अप्रत्याशित परिणाम हो सकते हैं।

निम्नलिखित उदाहरण पर विचार करें:

>>> p = Person(name='Fred')
>>> p.save(using='first')  # (statement 1)
>>> p.save(using='second') # (statement 2)

कथन 1 में, एक नया Person ऑब्जेक्ट first डेटाबेस में सहेजा गया है। इस समय, p पास प्राथमिक कुंजी नहीं है, इसलिए Django SQL INSERT स्टेटमेंट जारी करता है। यह एक प्राथमिक कुंजी बनाता है, और Django उस प्राथमिक कुंजी को p असाइन करता है।

जब स्टेटमेंट 2 में सेव होता है, p पहले से ही एक प्राथमिक कुंजी है, और Django नए डेटाबेस पर उस प्राथमिक कुंजी का उपयोग करने का प्रयास करेगा। यदि second डेटाबेस में प्राथमिक कुंजी मूल्य उपयोग में नहीं है, तो आपको कोई समस्या नहीं होगी - ऑब्जेक्ट को नए डेटाबेस में कॉपी किया जाएगा।

हालांकि, यदि p की प्राथमिक कुंजी पहले से ही second डेटाबेस पर उपयोग में है, तो p को सहेजे जाने पर second डेटाबेस में मौजूदा ऑब्जेक्ट को ओवरराइड किया जाएगा।

आप इससे दो तरह से बच सकते हैं। सबसे पहले, आप उदाहरण की प्राथमिक कुंजी को साफ़ कर सकते हैं। यदि किसी ऑब्जेक्ट में कोई प्राथमिक कुंजी नहीं है, तो second डेटाबेस पर डेटा के किसी भी नुकसान से बचने के लिए, Django इसे एक नई वस्तु के रूप में मानेगा:

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.pk = None # Clear the primary key.
>>> p.save(using='second') # Write a completely new object.

दूसरा विकल्प यह है कि Django SQL INSERT करता है यह सुनिश्चित करने के save() को save() लिए force_insert विकल्प का उपयोग INSERT :

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.save(using='second', force_insert=True)

यह सुनिश्चित करेगा कि Fred नाम का व्यक्ति दोनों डेटाबेस पर एक ही प्राथमिक कुंजी रखेगा। यदि आप second डेटाबेस पर सहेजने का प्रयास करते हैं तो प्राथमिक कुंजी पहले से ही उपयोग में है, एक त्रुटि उठाई जाएगी।

से हटाने के लिए डेटाबेस का चयन करना

डिफ़ॉल्ट रूप से, किसी मौजूदा ऑब्जेक्ट को हटाने के लिए कॉल को उसी डेटाबेस पर निष्पादित किया जाएगा जिसका उपयोग पहली जगह में ऑब्जेक्ट को प्राप्त करने के लिए किया गया था:

>>> u = User.objects.using('legacy_users').get(username='fred')
>>> u.delete() # will delete from the `legacy_users` database

उस डेटाबेस को निर्दिष्ट करने के लिए जिसमें से एक मॉडल हटा दिया जाएगा, Model.delete() विधि के लिए एक कीवर्ड तर्क using । यह तर्क save() using करते using कीवर्ड तर्क की तरह काम करता है।

उदाहरण के लिए, यदि आप किसी उपयोगकर्ता को legacy_users डेटाबेस से legacy_users डेटाबेस में माइग्रेट कर रहे हैं, तो आप इन आदेशों का उपयोग कर सकते हैं:

>>> user_obj.save(using='new_users')
>>> user_obj.delete(using='legacy_users')

एकाधिक डेटाबेस वाले प्रबंधकों का उपयोग करना

प्रबंधकों को गैर-डिफ़ॉल्ट डेटाबेस तक पहुँच देने के लिए db_manager() पद्धति का उपयोग करें।

उदाहरण के लिए, User.objects.create_user() कि आपके पास एक कस्टम प्रबंधक विधि है जो डेटाबेस को छूती है - User.objects.create_user() । क्योंकि create_user() एक प्रबंधक विधि है, QuerySet विधि नहीं, आप User.objects.using('new_users').create_user() नहीं कर सकते हैं User.objects.using('new_users').create_user() । ( create_user() विधि केवल User.objects पर उपलब्ध है, प्रबंधक, प्रबंधक से प्राप्त QuerySet ऑब्जेक्ट पर नहीं।) समाधान db_manager() का उपयोग db_manager() , इस तरह:

User.objects.db_manager('new_users').create_user(...)

db_manager() आपके द्वारा निर्दिष्ट डेटाबेस के लिए प्रबंधक की एक प्रति लौटाता है।

कई डेटाबेस के साथ get_queryset() का उपयोग करना

यदि आप अपने प्रबंधक पर get_queryset() को ओवरराइड कर रहे हैं, तो या तो पैरेंट पर विधि ( super() का उपयोग करके super() को कॉल करना सुनिश्चित करें या प्रबंधक पर _db विशेषता का उचित हैंडलिंग (डेटाबेस के नाम से युक्त एक स्ट्रिंग) करें उपयोग)।

उदाहरण के लिए, यदि आप QuerySet विधि से एक कस्टम QuerySet वर्ग वापस करना चाहते हैं, तो आप ऐसा कर सकते हैं:

class MyManager(models.Manager):
    def get_queryset(self):
        qs = CustomQuerySet(self.model)
        if self._db is not None:
            qs = qs.using(self._db)
        return qs

Django के व्यवस्थापक इंटरफ़ेस में कई डेटाबेस एक्सपोज़ करना

Django के व्यवस्थापक के पास कई डेटाबेस के लिए कोई स्पष्ट समर्थन नहीं है। यदि आप अपने राउटर श्रृंखला द्वारा निर्दिष्ट डेटाबेस के अलावा किसी मॉडल पर एक व्यवस्थापक इंटरफ़ेस प्रदान करना चाहते हैं, तो आपको कस्टम ModelAdmin वर्ग लिखना होगा जो व्यवस्थापक को सामग्री के लिए एक विशिष्ट डेटाबेस का उपयोग करने के लिए निर्देशित करेगा।

ModelAdmin ऑब्जेक्ट्स में पाँच तरीके होते हैं जिनके लिए कई-डेटाबेस समर्थन के लिए अनुकूलन की आवश्यकता होती है:

class MultiDBModelAdmin(admin.ModelAdmin):
    # A handy constant for the name of the alternate database.
    using = 'other'

    def save_model(self, request, obj, form, change):
        # Tell Django to save objects to the 'other' database.
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        # Tell Django to delete objects from the 'other' database
        obj.delete(using=self.using)

    def get_queryset(self, request):
        # Tell Django to look for objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)

यहां प्रदान किया गया कार्यान्वयन एक बहु-डेटाबेस रणनीति को लागू करता है जहां किसी विशेष प्रकार की सभी वस्तुओं को एक विशिष्ट डेटाबेस पर संग्रहीत किया जाता है (उदाहरण के लिए, सभी User ऑब्जेक्ट other डेटाबेस में हैं)। यदि आपके कई डेटाबेस का उपयोग अधिक जटिल है, तो आपके ModelAdmin को उस रणनीति को प्रतिबिंबित करने की आवश्यकता होगी।

InlineModelAdmin ऑब्जेक्ट्स को एक समान फैशन में संभाला जा सकता है। उन्हें तीन अनुकूलित तरीकों की आवश्यकता होती है:

class MultiDBTabularInline(admin.TabularInline):
    using = 'other'

    def get_queryset(self, request):
        # Tell Django to look for inline objects on the 'other' database.
        return super().get_queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)

एक बार जब आप अपनी मॉडल व्यवस्थापक परिभाषाएँ लिख लेते हैं, तो उन्हें किसी भी Admin उदाहरण के साथ पंजीकृत किया जा सकता है:

from django.contrib import admin

# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
    model = Book

class PublisherAdmin(MultiDBModelAdmin):
    inlines = [BookInline]

admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)

othersite = admin.AdminSite('othersite')
othersite.register(Publisher, MultiDBModelAdmin)

यह उदाहरण दो व्यवस्थापक साइट सेट करता है। पहली साइट पर, Author और Publisher वस्तुएं उजागर होती हैं; Publisher वस्तुओं में उस प्रकाशक द्वारा प्रकाशित पुस्तकों को दर्शाने वाली सारणीबद्ध इनलाइन होती है। दूसरी साइट केवल प्रकाशकों को उजागर करती है, बिना इनलाइन के।

कई डेटाबेस के साथ कच्चे कर्सर का उपयोग करना

यदि आप एक से अधिक डेटाबेस का उपयोग कर रहे हैं, तो आप किसी विशिष्ट डेटाबेस के लिए कनेक्शन (और कर्सर) प्राप्त करने के लिए django.db.connections का उपयोग कर सकते हैं। django.db.connections एक शब्दकोश जैसी वस्तु है, जो आपको इसके उपनाम का उपयोग करके एक विशिष्ट कनेक्शन प्राप्त करने की अनुमति देती है:

from django.db import connections
with connections['my_db_alias'].cursor() as cursor:
    ...

कई डेटाबेस की सीमाएँ

क्रॉस-डेटाबेस संबंध

Django वर्तमान में विदेशी कुंजी या कई-से-कई रिश्तों को कई डेटाबेसों के लिए कोई समर्थन प्रदान नहीं करता है। यदि आपने राउटर का उपयोग विभिन्न डेटाबेस में विभाजन को करने के लिए किया है, तो उन मॉडलों द्वारा परिभाषित किसी भी विदेशी कुंजी और कई-से-कई संबंध एकल डेटाबेस के लिए आंतरिक होने चाहिए।

यह संदर्भात्मक अखंडता के कारण है। दो वस्तुओं के बीच संबंध बनाए रखने के लिए, Django को यह जानना होगा कि संबंधित वस्तु की प्राथमिक कुंजी वैध है। यदि प्राथमिक कुंजी को एक अलग डेटाबेस पर संग्रहीत किया जाता है, तो प्राथमिक कुंजी की वैधता का आसानी से मूल्यांकन करना संभव नहीं है।

यदि आप InnoDB के साथ Postgres, Oracle, या MySQL का उपयोग कर रहे हैं, तो इसे डेटाबेस अखंडता स्तर पर लागू किया जाता है - डेटाबेस स्तर की मुख्य बाधाएं उन संबंधों के निर्माण को रोकती हैं जिन्हें मान्य नहीं किया जा सकता है।

हालाँकि, यदि आप MyISAM तालिकाओं के साथ SQLite या MySQL का उपयोग कर रहे हैं, तो कोई लागू संदर्भात्मक अखंडता नहीं है; नतीजतन, आप विदेशी डेटाबेस को 'नकली' पार करने में सक्षम हो सकते हैं। हालाँकि, यह कॉन्फ़िगरेशन आधिकारिक रूप से Django द्वारा समर्थित नहीं है।

कंट्राब ऐप्स का व्यवहार

कई कंट्रिब ऐप्स में मॉडल शामिल हैं, और कुछ ऐप दूसरों पर निर्भर हैं। चूंकि क्रॉस-डेटाबेस रिश्ते असंभव हैं, इसलिए यह कुछ प्रतिबंध बनाता है कि आप इन मॉडलों को डेटाबेस में कैसे विभाजित कर सकते हैं:

  • sites.Site , sites.Site , sites.Site और sites.Site हर एक को उपयुक्त राउटर को देखते हुए किसी भी डेटाबेस में स्टोर किया जा सकता है।
  • auth मॉडल - User , Group और Permission - एक साथ जुड़े हुए हैं और ContentType से जुड़े हुए हैं, इसलिए उन्हें सामग्री डेटाबेस के समान डेटाबेस में संग्रहीत किया जाना चाहिए।
  • admin निर्भर करता है, इसलिए इसके मॉडल को डेटाबेस के समान डेटाबेस में होना चाहिए।
  • flatpages और redirects sites पर निर्भर sites , इसलिए उनके मॉडल sites के समान डेटाबेस में होने चाहिए।

इसके अलावा, कुछ ऑब्जेक्ट्स स्वचालित रूप से बनाए जाते हैं जब migrate डेटाबेस में उन्हें रखने के लिए एक टेबल बनाता है:

  • एक डिफ़ॉल्ट Site ,
  • प्रत्येक मॉडल के लिए एक ContentType (उस डेटाबेस में संग्रहीत नहीं किए गए सहित),
  • प्रत्येक मॉडल के लिए तीन Permission (उन डेटाबेस में संग्रहीत नहीं हैं सहित)।

कई डेटाबेस के साथ सामान्य सेटअप के लिए, इन ऑब्जेक्ट्स को एक से अधिक डेटाबेस में रखना उपयोगी नहीं है। सामान्य सेटअप में प्राथमिक / प्रतिकृति और बाहरी डेटाबेस से जुड़ना शामिल है। इसलिए, एक डेटाबेस राउटर लिखने की सिफारिश की जाती है जो इन तीन मॉडलों को केवल एक डेटाबेस में सिंक्रनाइज़ करने की अनुमति देता है। Contrib और तृतीय-पक्ष एप्लिकेशन के लिए समान दृष्टिकोण का उपयोग करें, जिन्हें कई डेटाबेस में अपनी तालिकाओं की आवश्यकता नहीं है।

चेतावनी

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