Django एक लोकप्रिय ढांचा है जिसे आप अपनी कंपनी के लिए एप्लिकेशन विकसित करने के लिए चुन सकते हैं। लेकिन क्या होगा यदि आप एक SaaS एप्लिकेशन बनाना चाहते हैं जिसका उपयोग कई क्लाइंट करेंगे? आपको कौन सा आर्किटेक्चर चुनना चाहिए? आइए देखें कि इस कार्य को कैसे पूरा किया जा सकता है। एकल-किरायेदार वास्तुकला सबसे सीधा तरीका यह है कि आपके पास मौजूद प्रत्येक ग्राहक के लिए एक अलग उदाहरण बनाया जाए। मान लीजिए कि हमारे पास एक Django एप्लिकेशन और एक डेटाबेस है। फिर, प्रत्येक क्लाइंट के लिए, हमें उसका अपना डेटाबेस और एप्लिकेशन इंस्टेंस चलाने की आवश्यकता है। इसका मतलब है कि प्रत्येक एप्लिकेशन इंस्टेंस में केवल एक किरायेदार है। इस दृष्टिकोण को लागू करना सरल है: आपको बस अपनी प्रत्येक सेवा का एक नया उदाहरण शुरू करना होगा। लेकिन साथ ही, यह एक समस्या भी पैदा कर सकता है: प्रत्येक ग्राहक बुनियादी ढांचे की करेगा। यदि आप केवल कुछ ग्राहक रखने की योजना बना रहे हैं या प्रत्येक उदाहरण छोटा है तो यह कोई बड़ी बात नहीं हो सकती है। लागत में उल्लेखनीय वृद्धि हालाँकि, मान लीजिए कि हम एक बड़ी कंपनी बना रहे हैं जो 100,000 संगठनों को एक कॉर्पोरेट मैसेंजर प्रदान करती है। कल्पना कीजिए, प्रत्येक नए ग्राहक के लिए संपूर्ण बुनियादी ढांचे की नकल करना कितना महंगा हो सकता है! और, जब हमें एप्लिकेशन संस्करण को अपडेट करने की आवश्यकता होती है, तो हमें इसे प्रत्येक क्लाइंट के लिए तैनात करने की आवश्यकता होती है, इसलिए । तैनाती भी धीमी हो जाएगी बहु-किरायेदार वास्तुकला एक और दृष्टिकोण है जो उस परिदृश्य में मदद कर सकता है जब हमारे पास एप्लिकेशन के लिए बहुत सारे ग्राहक हों: एक बहु-किरायेदार वास्तुकला। इसका मतलब है कि हमारे पास कई ग्राहक हैं, जिन्हें हम कहते हैं, लेकिन वे सभी एप्लिकेशन के केवल एक उदाहरण का उपयोग करते हैं। किरायेदार जबकि यह आर्किटेक्चर प्रत्येक ग्राहक के लिए समर्पित उदाहरणों की उच्च लागत की समस्या को हल करता है, यह एक नई समस्या पेश करता है: हम कैसे सुनिश्चित कर सकते हैं कि ग्राहक का डेटा अन्य ग्राहकों से सुरक्षित रूप से अलग है? हम निम्नलिखित दृष्टिकोणों पर चर्चा करेंगे: उपयोग करना: हम विदेशी कुंजी द्वारा यह पहचान सकते हैं कि कौन सा किरायेदार डेटा का मालिक है जिसे हमें प्रत्येक डेटाबेस तालिका में जोड़ने की आवश्यकता है। साझा डेटाबेस और साझा डेटाबेस स्कीमा का उपयोग करना: इस तरह, हमें कई डेटाबेस उदाहरणों को बनाए रखने की आवश्यकता नहीं होगी, लेकिन किरायेदार डेटा अलगाव का एक अच्छा स्तर प्राप्त होगा। एक साझा डेटाबेस, लेकिन अलग डेटाबेस स्कीमा का उपयोग करना: यह एकल-किरायेदार उदाहरण के समान दिखता है, लेकिन समान नहीं होगा, क्योंकि हम अभी भी एक साझा एप्लिकेशन इंस्टेंस का उपयोग करेंगे और किरायेदार की जांच करके चयन करेंगे कि किस डेटाबेस का उपयोग करना है। अलग-अलग डेटाबेस का आइए इन विचारों को गहराई से देखें और देखें कि इन्हें Django एप्लिकेशन के साथ कैसे एकीकृत किया जाए। साझा स्कीमा के साथ एक साझा डेटाबेस यह विकल्प सबसे पहले दिमाग में आ सकता है: तालिकाओं में एक फॉरेनकी जोड़ना, और प्रत्येक किरायेदार के लिए उचित डेटा का चयन करने के लिए इसका उपयोग करना। हालाँकि, इसका एक बड़ा नुकसान है: किरायेदारों का डेटा बिल्कुल भी अलग नहीं होता है, इसलिए एक छोटी सी प्रोग्रामिंग त्रुटि किरायेदार के डेटा को गलत क्लाइंट को लीक करने के लिए पर्याप्त हो सकती है। आइए से डेटाबेस संरचना का एक उदाहरण लें: Django दस्तावेज़ from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) हमें यह पहचानने की आवश्यकता होगी कि कौन से रिकॉर्ड किस किरायेदार के स्वामित्व में हैं। इसलिए, हमें प्रत्येक मौजूदा तालिका में एक तालिका और एक विदेशी कुंजी जोड़ने की आवश्यकता है: Tenant class Tenant(models.Model): name = models.CharField(max_length=200) class Question(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") class Choice(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) कोड को थोड़ा सरल बनाने के लिए, हम एक अमूर्त आधार मॉडल बना सकते हैं जिसे हमारे द्वारा बनाए गए प्रत्येक दूसरे मॉडल में पुन: उपयोग किया जाएगा। class Tenant(models.Model): name = models.CharField(max_length=200) class BaseModel(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) class Meta: abstract = True class Question(BaseModel): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") class Choice(BaseModel): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) जैसा कि आप देख सकते हैं, यहां कम से कम दो प्रमुख जोखिम हैं: एक , या एक डेवलपर नए मॉडल में एक किरायेदार फ़ील्ड जोड़ना भूल सकता है डेवलपर डेटा फ़िल्टर करते समय इस फ़ील्ड का उपयोग करना भूल सकता है। इस उदाहरण का स्रोत कोड GitHub पर पाया जा सकता है: । https://github.com/bp72/django-multitenancy-examples/tree/main/01_shared_database_shared_schema अलग-अलग स्कीमा के साथ एक साझा डेटाबेस साझा स्कीमा के जोखिमों को ध्यान में रखते हुए, आइए एक अन्य विकल्प पर विचार करें: डेटाबेस अभी भी साझा किया जाएगा, लेकिन हम प्रत्येक किरायेदार के लिए एक समर्पित स्कीमा बनाएंगे। कार्यान्वयन के लिए, हम एक लोकप्रिय लाइब्रेरी ( ) को देख सकते हैं। django-किरायेदारों दस्तावेज़ीकरण आइए अपने छोटे प्रोजेक्ट में जोड़ें (आधिकारिक इंस्टॉलेशन चरण पाए जा सकते हैं)। django-tenants यहां पहला चरण के माध्यम से लाइब्रेरी इंस्टालेशन है: pip pip install django-tenants मॉडल बदलें: मॉडल अब एक अलग ऐप में होगा और मॉडल का अब किरायेदार के साथ कोई संबंध नहीं होगा। चूंकि अलग-अलग किरायेदारों का डेटा अलग-अलग स्कीमा में होगा, इसलिए हमें अब अलग-अलग रिकॉर्ड को किरायेदार पंक्तियों से जोड़ने की आवश्यकता नहीं होगी। Tenant Question Choice फ़ाइल किरायेदार/मॉडल.py from django.db import models from django_tenants.models import TenantMixin, DomainMixin class Tenant(TenantMixin): name = models.CharField(max_length=200) # default true, schema will be automatically created and synced when it is saved auto_create_schema = True class Domain(DomainMixin): # a required table for django-tenants too ... फ़ाइल poll/models.py from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) ध्यान दें कि प्रश्न और विकल्प के पास अब किरायेदार के लिए कोई विदेशी कुंजी नहीं है! दूसरी चीज़ जो बदली गई है वह यह है कि किरायेदार अब एक अलग ऐप में है: यह न केवल डोमेन को अलग करने के लिए है बल्कि महत्वपूर्ण भी है क्योंकि हमें तालिका को साझा स्कीमा में संग्रहीत करने की आवश्यकता होगी, और प्रत्येक किरायेदार के लिए तालिकाएँ बनाई जाएंगी स्कीमा. tenants polls एकाधिक स्कीमा और किरायेदारों का समर्थन करने के लिए फ़ाइल में परिवर्तन करें: settings.py DATABASES = { 'default': { 'ENGINE': 'django_tenants.postgresql_backend', # .. } } DATABASE_ROUTERS = ( 'django_tenants.routers.TenantSyncRouter', ) MIDDLEWARE = ( 'django_tenants.middleware.main.TenantMainMiddleware', #... ) TEMPLATES = [ { #... 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.request', #... ], }, }, ] SHARED_APPS = ( 'django_tenants', # mandatory 'tenants', # you must list the app where your tenant model resides in 'django.contrib.contenttypes', # everything below here is optional 'django.contrib.auth', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.admin', ) TENANT_APPS = ( # your tenant-specific apps 'polls', ) INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS] TENANT_MODEL = "tenants.Tenant" TENANT_DOMAIN_MODEL = "tenants.Domain" आगे, आइए माइग्रेशन बनाएं और लागू करें: python manage.py makemigrations python manage.py migrate_schemas --shared परिणामस्वरूप, हम देखेंगे कि सार्वजनिक स्कीमा बनाई जाएगी और इसमें केवल साझा तालिकाएँ होंगी। हमें स्कीमा के लिए एक डिफ़ॉल्ट किरायेदार बनाने की आवश्यकता होगी: public python manage.py create_tenant --domain-domain=default.com --schema_name=public --name=default_tenant यदि पूछा जाए तो को पर सेट करें। is_primary True और फिर, हम सेवा के वास्तविक किरायेदार बनाना शुरू कर सकते हैं: python manage.py create_tenant --domain-domain=tenant1.com --schema_name=tenant1 --name=tenant_1 python manage.py create_tenant --domain-domain=tenant2.com --schema_name=tenant2 --name=tenant_2 ध्यान दें कि डेटाबेस में अब 2 और स्कीमा हैं जिनमें टेबल हैं: polls अब, जब आप किरायेदारों के लिए सेट किए गए डोमेन पर एपीआई कॉल करेंगे तो आपको विभिन्न स्कीमा से प्रश्न और विकल्प मिलेंगे - सब हो गया! हालाँकि यदि आप मौजूदा ऐप को माइग्रेट करते हैं तो सेटअप अधिक जटिल और शायद और भी कठिन लगता है, फिर भी इस दृष्टिकोण में डेटा की सुरक्षा जैसे कई फायदे हैं। उदाहरण का कोड पाया जा सकता है। यहां अलग डेटाबेस आखिरी दृष्टिकोण जिस पर हम आज चर्चा करेंगे वह और भी आगे जा रहा है और किरायेदारों के लिए अलग डेटाबेस बना रहा है। इस बार, हमारे पास कुछ डेटाबेस होंगे: हम साझा किए गए डेटा जैसे किरायेदार की मैपिंग को डेटाबेस के नामों में में संग्रहीत करेंगे और प्रत्येक किरायेदार के लिए एक अलग डेटाबेस बनाएंगे। default_db फिर हमें सेटिंग्स.py में डेटाबेस कॉन्फ़िगरेशन सेट करने की आवश्यकता होगी: DATABASES = { 'default': { 'NAME': 'default_db', ... }, 'tenant_1': { 'NAME': 'tenant_1', ... }, 'tenant_2': { 'NAME': 'tenant_2', ... }, } और अब, हम QuerySet विधि का कॉल करके प्रत्येक किरायेदार के लिए डेटा प्राप्त करने में सक्षम होंगे: using Questions.objects.using('tenant_1')… विधि का नकारात्मक पक्ष यह है कि आपको इसका उपयोग करके प्रत्येक डेटाबेस पर सभी माइग्रेशन लागू करने की आवश्यकता होगी: python manage.py migrate --database=tenant_1 के उपयोग की तुलना में या साझा स्कीमा दृष्टिकोण में केवल एक विदेशी कुंजी का उपयोग करने की तुलना में, प्रत्येक किरायेदार के लिए एक नया डेटाबेस बनाना भी कम सुविधाजनक हो सकता है। django-tenants दूसरी ओर, किरायेदार के डेटा का अलगाव वास्तव में अच्छा है: डेटाबेस को भौतिक रूप से अलग किया जा सकता है। एक और फायदा यह है कि हम केवल Postgresql का उपयोग करके सीमित नहीं रहेंगे क्योंकि यह के लिए आवश्यक है, हम कोई भी इंजन चुन सकते हैं जो हमारी आवश्यकताओं के अनुरूप होगा। django-tenants एकाधिक डेटाबेस विषय पर अधिक जानकारी Django में पाई जा सकती है। दस्तावेज़ तुलना एकल किरायेदार साझा स्कीमा के साथ एमटी अलग स्कीमा के साथ एमटी अलग डेटाबेस के साथ एमटी डेटा अलगाव ✅उच्च ❌न्यूनतम ✅उच्च ✅उच्च गलती से डेटा लीक होने का खतरा ✅कम ❌उच्च ✅कम ✅कम बुनियादी ढांचे की लागत ❌प्रत्येक किरायेदार के साथ उच्चतर ✅निचला ✅निचला ✅❌ एकल-किरायेदार से कम परिनियोजन गति ❌प्रत्येक किरायेदार के साथ कम करें ✅ ✅❌ माइग्रेशन धीमा होगा क्योंकि उन्हें प्रत्येक स्कीमा के लिए निष्पादित करने की आवश्यकता होगी ✅❌ माइग्रेशन धीमा होगा क्योंकि उन्हें प्रत्येक डेटाबेस के लिए निष्पादित करने की आवश्यकता होगी कार्यान्वयन में आसान ✅ ❌ यदि सेवा पहले से ही एकल-किरायेदार ऐप के रूप में लागू की गई थी तो बहुत सारे बदलावों की आवश्यकता है ✅ ✅ निष्कर्ष उपरोक्त सभी को सारांशित करने के लिए, ऐसा लगता है कि समस्या का कोई समाधान नहीं है, प्रत्येक दृष्टिकोण के अपने फायदे और नुकसान हैं, इसलिए यह डेवलपर्स पर निर्भर है कि वे क्या समझौता कर सकते हैं। अलग-अलग डेटाबेस किरायेदार के डेटा के लिए सबसे अच्छा अलगाव प्रदान करते हैं और लागू करने में आसान होते हैं, हालांकि, रखरखाव के लिए आपको अधिक लागत आती है: अद्यतन करने के लिए डेटाबेस, डेटाबेस कनेक्शन संख्या अधिक होती है। कार्यान्वयन के लिए एक अलग स्कीमा बिट कॉम्प्लेक्स वाला एक साझा डेटाबेस और माइग्रेशन के साथ कुछ समस्याएं हो सकती हैं। एकल किरायेदार को लागू करना सबसे सरल है, लेकिन इसमें आपको संसाधनों की अधिक खपत का खर्च उठाना पड़ता है क्योंकि आपके पास प्रति किरायेदार के पास आपकी सेवा की पूरी प्रति होती है।