इस ब्लॉग पोस्ट में Django 1.8 - ArrayField, HStoreField, और Range Fields में पेश किए गए नए PostgreSQL-विशिष्ट ModelFields का उपयोग करने का तरीका बताया गया है।
यह पोस्ट मार्क टैमलिन द्वारा एक साथ रखे गए इस किकस्टार्टर अभियान के भयानक समर्थकों को समर्पित है, जो इसे बनाने वाला सच्चा नाटक है।
प्लायाज़ क्लब?
चूंकि मैं एक बहुत बड़ा गीक हूं और मेरे पास वास्तविक Playaz क्लब में शामिल होने का कोई मौका नहीं है (और क्योंकि दिन में 4 Tay बम था), मैंने अपना खुद का वर्चुअल ऑनलाइन Playaz क्लब बनाने का फैसला किया। वह वास्तव में क्या है? समान विचारधारा वाले व्यक्तियों के एक छोटे समूह पर लक्षित एक निजी, केवल-आमंत्रित सामाजिक नेटवर्क।
इस पोस्ट के लिए, हम उपयोगकर्ता मॉडल पर ध्यान केंद्रित करने जा रहे हैं और यह पता लगाने जा रहे हैं कि कैसे Django की नई PostgreSQL सुविधाएँ मॉडलिंग का समर्थन करती हैं। हम जिन नई सुविधाओं का उल्लेख कर रहे हैं, वे केवल PostgreSQL हैं, इसलिए जब तक आपके पास आपका डेटाबेस ENGINE
न हो, तब तक इसे आज़माने की जहमत न उठाएं। django.db.backends.postgresql_psycopg2
. के बराबर . आपको psycopg2
. के संस्करण>=2.5 की आवश्यकता होगी . ठीक है, चलो यह करते हैं।
होला अगर तुम मेरे साथ हो! :)पी>
Playa के प्रतिनिधि की मॉडलिंग करना
प्रत्येक नाटक को एक प्रतिनिधि मिला, और वे चाहते हैं कि पूरी दुनिया उनके प्रतिनिधि के बारे में जाने। तो चलिए एक उपयोगकर्ता प्रोफ़ाइल बनाते हैं (उर्फ "प्रतिनिधि") जो हमारे प्रत्येक playaz को उनके व्यक्तित्व को व्यक्त करने की अनुमति देता है।
यहाँ एक playaz प्रतिनिधि के लिए मूल मॉडल है:
from django.db import models
from django.contrib.auth.models import User
class Rep(models.Model):
playa = models.OneToOneField(User)
hood = models.CharField(max_length=100)
area_code = models.IntegerField()
ऊपर 1.8 के लिए कुछ खास नहीं। आधार Django उपयोगकर्ता का विस्तार करने के लिए बस एक मानक मॉडल, क्योंकि प्लाया को अभी भी उपयोगकर्ता नाम और ईमेल पते की आवश्यकता है, है ना? साथ ही हमने playaz हुड और एरिया कोड को स्टोर करने के लिए दो नए फ़ील्ड जोड़े हैं।
बैंकरोल और रेंजफ़ील्ड
एक नाटक के लिए, अपने हुड को दोहराना हमेशा पर्याप्त नहीं होता है। Playaz अक्सर अपने बैंकरोल का दिखावा करना पसंद करता है, लेकिन साथ ही लोगों को यह नहीं बताना चाहता कि वह बैंकरोल कितना बड़ा है। हम इसे नए पोस्टग्रेज रेंज फील्ड्स में से एक के साथ मॉडल कर सकते हैं। बेशक हम BigIntegerRangeField
. का उपयोग करेंगे बड़े पैमाने पर अंकों के बेहतर मॉडल के लिए, ठीक है?
bankroll = pgfields.BigIntegerRangeField(default=(10, 100))
रेंज फील्ड्स psycopg2 रेंज ऑब्जेक्ट्स पर आधारित होते हैं और इन्हें न्यूमेरिक और डेटरेंज के लिए इस्तेमाल किया जा सकता है। बैंकरोल फ़ील्ड को डेटाबेस में माइग्रेट करने के साथ, हम अपने रेंज फ़ील्ड को एक रेंज ऑब्जेक्ट पास करके इंटरैक्ट कर सकते हैं, इसलिए अपना पहला प्लेआ बनाना कुछ इस तरह दिखाई देगा:
>>>>>> from playa.models import Rep
>>> from django.contrib.auth.models import User
>>> calvin = User.objects.create_user(username="snoop", password="dogg")
>>> calvins_rep = Rep(hood="Long Beach", area_code=213)
>>> calvins_rep.bankroll = (100000000, 150000000)
>>> calvins_rep.playa = calvin
>>> calvins_rep.save()
इस लाइन पर ध्यान दें:calvins_rep.bankroll = (100000000, 150000000)
. यहां हम एक साधारण टपल का उपयोग करके एक श्रेणी फ़ील्ड सेट कर रहे हैं। NumericRange
. का उपयोग करके मान सेट करना भी संभव है इस तरह की वस्तु:
from psycopg2.extras import NumericRange
br = NumericRange(lower=100000000, upper=150000000)
calvin.rep.bankroll = br
calvin.rep.save()
यह अनिवार्य रूप से टपल का उपयोग करने जैसा ही है। हालांकि, NumericRange
. के बारे में जानना महत्वपूर्ण है ऑब्जेक्ट के रूप में मॉडल को फ़िल्टर करने के लिए उपयोग किया जाता है। उदाहरण के लिए, यदि हम उन सभी नाटकों को खोजना चाहते हैं जिनका बैंकरोल 50 मिलियन से अधिक था (मतलब पूरी बैंकरोल रेंज 50 मिलियन से अधिक है):
Rep.objects.filter(bankroll__fully_gt=NumericRange(50000000, 50000000))
और वह उन नाटकों की सूची वापस कर देगा। वैकल्पिक रूप से, यदि हम उन सभी नाटकों को खोजना चाहते हैं जिनका बैंकरोल "कहीं 10 से 15 मिलियन रेंज के आसपास" है, तो हम इसका उपयोग कर सकते हैं:
Rep.objects.filter(bankroll__overlap=NumericRange(10000000, 15000000))
यह उन सभी नाटकों को वापस कर देगा जिनकी बैंकरोल सीमा है जिसमें कम से कम 10 से 15 मिलियन की सीमा का कुछ हिस्सा शामिल है। एक अधिक संपूर्ण क्वेरी वे सभी नाटक होंगे जिनमें एक सीमा के बीच पूरी तरह से एक बैंकरोल होता है, यानी हर कोई जो कम से कम 10 मिलियन कमा रहा है लेकिन 15 मिलियन से अधिक नहीं। वह क्वेरी कुछ इस तरह दिखेगी:
Rep.objects.filter(bankroll__contained_by=NumericRange(10000000, 15000000))
श्रेणी-आधारित प्रश्नों के बारे में अधिक जानकारी यहां पाई जा सकती है।
ऐरेफ़ील्ड के रूप में स्किल्ज़
यह सब बैंकरोल के बारे में नहीं है, playaz को कौशल मिला है, सभी प्रकार के कौशल हैं। आइए उन्हें ArrayField के साथ मॉडल करें।
skillz = pgfields.ArrayField(
models.CharField(max_length=100, blank=True),
blank = True,
null = True,
)
ArrayField
घोषित करने के लिए हमें इसे पहला तर्क देना होगा, जो कि बेसफील्ड है। पायथन सूचियों के विपरीत, ArrayFields को सूची के प्रत्येक तत्व को एक ही प्रकार के रूप में घोषित करना चाहिए। बेसफ़ील्ड घोषणा करता है कि यह किस प्रकार का है, और यह कोई भी मानक मॉडल फ़ील्ड प्रकार हो सकता है। उपरोक्त मामले में, हमने अभी-अभी एक CharField
. का उपयोग किया है हमारे बेसटाइप के रूप में, जिसका अर्थ है skillz
स्ट्रिंग्स की एक सरणी होगी।
मूल्यों को ArrayField
. में संग्रहीत करना बिल्कुल वैसा ही है जैसा आप उम्मीद करते हैं:
>>> from django.contrib.auth.models import User
>>> calvin = User.objects.get(username='snoop')
>>> calvin.rep.skillz = ['ballin', 'rappin', 'talk show host', 'merchandizn']
>>> calvin.rep.save()
कौशल द्वारा नाटक ढूँढना
यदि हमें किसी विशेष कौशल के साथ एक विशेष नाटक की आवश्यकता है, तो हम उन्हें कैसे खोजेंगे? __contains
. का उपयोग करें फ़िल्टर:
Rep.objects.filter(skillz__contains=['rappin'])
नाटकों के लिए जिनके पास कोई भी कौशल है ['रैपिन', 'डीजिंग', 'उत्पादन'] लेकिन कोई अन्य कौशल नहीं है, आप ऐसा प्रश्न कर सकते हैं:
Rep.objects.filter(skillz__contained_by=['rappin', 'djing', 'producing'])
या यदि आप किसी ऐसे व्यक्ति को ढूंढना चाहते हैं जिसके पास कौशल की एक निश्चित सूची है:
Rep.objects.filter(skillz__overlap=['rappin', 'djing', 'producing'])
आप केवल उन्हीं लोगों को ढूंढ सकते हैं जिन्होंने किसी कौशल को अपने पहले कौशल के रूप में सूचीबद्ध किया है (क्योंकि हर कोई अपने सर्वोत्तम कौशल को पहले सूचीबद्ध करता है):
Rep.objects.filter(skillz__0='ballin')
HStore के रूप में खेल
खेल को एक नाटक के विविध, यादृच्छिक कौशल की सूची के रूप में माना जा सकता है। चूंकि गेम सभी प्रकार की चीजों को फैलाता है, आइए इसे एक HStore फ़ील्ड के रूप में मॉडल करें, जिसका मूल रूप से मतलब है कि हम वहां किसी भी पुराने पायथन डिक्शनरी को चिपका सकते हैं:
game = pgfields.HStoreField()
<ब्लॉकक्वॉट> हमने अभी-अभी यहाँ क्या किया, इसके बारे में सोचने के लिए एक सेकंड का समय लें। एचस्टोर बहुत बड़ा है। यह मूल रूप से पोस्टग्रेएसक्यूएल के ठीक अंदर "नोएसक्यूएल" -टाइप डेटा स्टोरेज की अनुमति देता है। साथ ही, चूंकि यह PostgreSQL के अंदर है, इसलिए हम (विदेशी कुंजियों के माध्यम से) लिंक कर सकते हैं, ऐसी तालिकाएँ जिनमें NoSQL डेटा होता है और जो नियमित SQL-प्रकार डेटा संग्रहीत करते हैं। आप दोनों को एक ही टेबल में अलग-अलग कॉलम पर स्टोर भी कर सकते हैं जैसा कि हम यहां कर रहे हैं। हो सकता है कि playas को अब उस जानकी, ऑल-टॉक MongoDB का उपयोग करने की आवश्यकता न हो…
कार्यान्वयन विवरण पर वापस आते हैं, यदि आप नए HStore फ़ील्ड को डेटाबेस में माइग्रेट करने का प्रयास करते हैं और इस त्रुटि के साथ समाप्त होते हैं-
django.db.utils.ProgrammingError: type "hstore" does not exist
-तो आपका PostgreSQL डेटाबेस 8.1 से पहले का है (अपग्रेड करने का समय, playa) या इसमें HStore एक्सटेंशन इंस्टॉल नहीं है। ध्यान रखें कि PostgreSQL में HStore एक्सटेंशन प्रति डेटाबेस स्थापित है न कि सिस्टम-वाइड। इसे अपने psql प्रांप्ट से स्थापित करने के लिए, निम्न SQL चलाएँ:
CREATE EXTENSION hstore
या यदि आप चाहें, तो आप इसे निम्न माइग्रेशन फ़ाइल के साथ SQL माइग्रेशन के माध्यम से कर सकते हैं (यह मानते हुए कि आप सुपरयुसर के रूप में डेटाबेस से जुड़े थे):
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunSQL("CREATE EXTENSION IF NOT EXISTS hstore")
]
अंत में, आपको यह भी सुनिश्चित करना होगा कि आपने 'django.contrib.postgres'
जोड़ा है 'settings.INSTALLED_APPS'
. पर HStore फ़ील्ड का उपयोग करने के लिए।
उस सेटअप से हम अपने HStoreField
. में डेटा जोड़ सकते हैं game
इस तरह एक शब्दकोश फेंक कर:
>>> calvin = User.objects.get(username="snoop")
>>> calvin.rep.game = {'best_album': 'Doggy Style', 'youtube-channel': \
'https://www.youtube.com/user/westfesttv', 'twitter_follows' : '11000000'}
>>> calvin.rep.save()
ध्यान रखें कि dict केवल सभी कुंजियों और मानों के लिए स्ट्रिंग्स का उपयोग करना चाहिए।
और अब कुछ और दिलचस्प उदाहरणों के लिए…
प्रस्ताव
आइए playaz गेम को खोजने के लिए एक "शो गेम" फ़ंक्शन लिखें और उस मैच के playaz की सूची लौटाएं। geeky शब्दों में, हम फ़ंक्शन में पारित किसी भी कुंजी के लिए HStore फ़ील्ड के माध्यम से खोज रहे हैं। यह कुछ इस तरह दिखता है:
def show_game(key):
return Rep.Objects.filter(game__has_key=key).values('game','playa__username')
ऊपर हमने has_key
. का उपयोग किया है एक क्वेरीसेट वापस करने के लिए HStore फ़ील्ड के लिए फ़िल्टर करें, फिर इसे मान फ़ंक्शन के साथ फ़िल्टर करें (मुख्य रूप से यह दिखाने के लिए कि आप django.contrib.postgres
को चेन कर सकते हैं। नियमित क्वेरी सेट सामग्री के साथ सामान)।
वापसी मूल्य शब्दकोशों की एक सूची होगी:
[
{'playa__username': 'snoop',
'game': {'twitter_follows': '11000000',
'youtube-channel': 'https://www.youtube.com/user/westfesttv',
'best_album': 'Doggy Style'
}
}
]
जैसा कि वे कहते हैं, गेम गेम को पहचानता है, और अब हम गेम भी खोज सकते हैं।
उच्च रोलर्स
अगर हम मानते हैं कि प्लेअज़ हमें उनके बैंकरोल के बारे में क्या बता रहा है, तो हम इसका उपयोग उन्हें श्रेणियों में रैंक करने के लिए कर सकते हैं (क्योंकि यह एक सीमा है)। आइए निम्न स्तरों के साथ बैंकरोल के आधार पर Playa रैंकिंग जोड़ें:
-
यंग हिरन - एक सौ से कम भव्य बैंकरोल
-
बल्ला - 'बैलिन' कौशल के साथ 100,000 से 500,000 के बीच बैंकरोल
-
playa - दो स्किल्ज़ और कुछ गेम के साथ 500,000 और 1,000,000 के बीच बैंकरोल
-
हाई रोलर - 1,000,000 से अधिक का बैंकरोल
-
ओ.जी. - कौशल 'गैंगस्टा' और गेम की "ओल्ड-स्कूल" है
बल्ला के लिए क्वेरी नीचे है। यह सख्त व्याख्या होगी, जो केवल उन्हीं को लौटाएगी जिनकी संपूर्ण बैंकरोल सीमा निर्दिष्ट सीमा के भीतर है:
Rep.objects.filter(bankroll__contained_by=[100000, 500000], skillz__contains=['ballin'])
बाकी को कुछ अभ्यास के लिए स्वयं आज़माएं। अगर आपको कुछ मदद चाहिए, तो डॉक्स पढ़ें।