मैंने कुछ ऐसा ही किया है जो बिंदु 1 के सबसे करीब है, लेकिन डिफ़ॉल्ट कनेक्शन सेट करने के लिए मिडलवेयर का उपयोग करने के बजाय Django डेटाबेस राउटर का उपयोग किया जाता है। यह एप्लिकेशन लॉजिक को प्रत्येक अनुरोध के लिए आवश्यक होने पर कई डेटाबेस का उपयोग करने की अनुमति देता है। प्रत्येक क्वेरी के लिए उपयुक्त डेटाबेस चुनना एप्लिकेशन लॉजिक पर निर्भर है, और यह इस दृष्टिकोण का बड़ा नकारात्मक पहलू है।
इस सेटअप के साथ, सभी डेटाबेस settings.DATABASES
. में सूचीबद्ध होते हैं , जिसमें डेटाबेस शामिल हैं जिन्हें ग्राहकों के बीच साझा किया जा सकता है। प्रत्येक मॉडल जो ग्राहक विशिष्ट होता है उसे एक Django ऐप में रखा जाता है जिसमें एक विशिष्ट ऐप लेबल होता है।
उदाहरण के लिए निम्न वर्ग एक मॉडल को परिभाषित करता है जो सभी ग्राहक डेटाबेस में मौजूद होता है।
class MyModel(Model):
....
class Meta:
app_label = 'customer_records'
managed = False
एक डेटाबेस राउटर को settings.DATABASE_ROUTERS
app_label
. द्वारा डेटाबेस अनुरोध को रूट करने के लिए श्रृंखला , कुछ इस तरह (पूर्ण उदाहरण नहीं):
class AppLabelRouter(object):
def get_customer_db(self, model):
# Route models belonging to 'myapp' to the 'shared_db' database, irrespective
# of customer.
if model._meta.app_label == 'myapp':
return 'shared_db'
if model._meta.app_label == 'customer_records':
customer_db = thread_local_data.current_customer_db()
if customer_db is not None:
return customer_db
raise Exception("No customer database selected")
return None
def db_for_read(self, model, **hints):
return self.get_customer_db(model, **hints)
def db_for_write(self, model, **hints):
return self.get_customer_db(model, **hints)
इस राउटर की खास बात है thread_local_data.current_customer_db()
बुलाना। राउटर का प्रयोग करने से पहले, कॉलर/एप्लिकेशन ने वर्तमान ग्राहक डीबी को thread_local_data
में सेट किया होगा . एक मौजूदा ग्राहक डेटाबेस को पुश/पॉप करने के लिए इस उद्देश्य के लिए एक पायथन संदर्भ प्रबंधक का उपयोग किया जा सकता है।
यह सब कॉन्फ़िगर किए जाने के बाद, एप्लिकेशन कोड कुछ इस तरह दिखता है, जहां UseCustomerDatabase
एक मौजूदा ग्राहक डेटाबेस नाम को thread_local_data
. में पुश/पॉप करने के लिए एक संदर्भ प्रबंधक है ताकि thread_local_data.current_customer_db()
राउटर के हिट होने पर सही डेटाबेस नाम लौटाएगा:
class MyView(DetailView):
def get_object(self):
db_name = determine_customer_db_to_use(self.request)
with UseCustomerDatabase(db_name):
return MyModel.object.get(pk=1)
यह पहले से ही काफी जटिल सेटअप है। यह काम करता है, लेकिन मैं जो कुछ फायदे और नुकसान के रूप में देखता हूं उसे संक्षेप में प्रस्तुत करने का प्रयास करूंगा:
फायदे
- डेटाबेस चयन लचीला है। यह एक ही क्वेरी में एकाधिक डेटाबेस का उपयोग करने की अनुमति देता है, अनुरोध में ग्राहक विशिष्ट और साझा डेटाबेस दोनों का उपयोग किया जा सकता है।
- डेटाबेस चयन स्पष्ट है (सुनिश्चित नहीं है कि यह एक फायदा या नुकसान है)। यदि आप किसी ग्राहक डेटाबेस को हिट करने वाली क्वेरी चलाने का प्रयास करते हैं, लेकिन एप्लिकेशन ने एक का चयन नहीं किया है, तो एक प्रोग्रामिंग त्रुटि का संकेत देने वाला एक अपवाद होगा।
- डेटाबेस राउटर का उपयोग करने से
USE db;
पर निर्भर होने के बजाय अलग-अलग होस्ट पर अलग-अलग डेटाबेस मौजूद रहते हैं। कथन जो अनुमान लगाता है कि सभी डेटाबेस एक ही कनेक्शन के माध्यम से सुलभ हैं।
नुकसान
- इसे सेटअप करना जटिल है, और इसे काम करने के लिए काफी कुछ परतें शामिल हैं।
- थ्रेड स्थानीय डेटा की आवश्यकता और उपयोग अस्पष्ट है।
- दृश्य डेटाबेस चयन कोड से अटे पड़े हैं। अनुरोध पैरामीटर के आधार पर डेटाबेस को स्वचालित रूप से चुनने के लिए क्लास आधारित दृश्यों का उपयोग करके इसे सारगर्भित किया जा सकता है, जैसे कि मिडलवेयर एक डिफ़ॉल्ट डेटाबेस चुनता है।
- डेटाबेस चुनने के लिए संदर्भ प्रबंधक को एक क्वेरीसेट के चारों ओर इस तरह से लपेटा जाना चाहिए कि क्वेरी का मूल्यांकन करते समय संदर्भ प्रबंधक अभी भी सक्रिय हो।
सुझाव
यदि आप लचीला डेटाबेस एक्सेस चाहते हैं, तो मैं Django के डेटाबेस राउटर का उपयोग करने का सुझाव दूंगा। मिडलवेयर या एक व्यू मिक्सिन का उपयोग करें जो अनुरोध मापदंडों के आधार पर कनेक्शन के लिए उपयोग करने के लिए स्वचालित रूप से एक डिफ़ॉल्ट डेटाबेस सेट करता है। उपयोग करने के लिए डिफ़ॉल्ट डेटाबेस को संग्रहीत करने के लिए आपको थ्रेड स्थानीय डेटा का सहारा लेना पड़ सकता है ताकि जब राउटर हिट हो, तो यह जान सके कि किस डेटाबेस को रूट करना है। यह Django को एक डेटाबेस के लिए अपने मौजूदा लगातार कनेक्शन का उपयोग करने की अनुमति देता है (जो अलग-अलग होस्ट पर रह सकता है यदि वांछित हो), और अनुरोध में सेट अप रूटिंग के आधार पर डेटाबेस का उपयोग करने के लिए चुनता है।
इस दृष्टिकोण का यह भी लाभ है कि यदि आवश्यक हो तो QuerySet using()
डिफ़ॉल्ट के अलावा किसी अन्य डेटाबेस का चयन करने के लिए कार्य करता है।