Django
क्वेरीसमूहों
खोज…
परिचय
एक Queryset
मूलरूप से एक से ली गई वस्तुओं की एक सूची है Model
, डेटाबेस प्रश्नों का एक संकलन से।
एक स्टैंडअलोन मॉडल पर सरल प्रश्न
यहाँ एक सरल मॉडल है जिसका उपयोग हम कुछ परीक्षण क्वेरीज़ चलाने के लिए करेंगे:
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
एक एकल मॉडल ऑब्जेक्ट प्राप्त करें जहां id / pk 4 है:
(यदि 4 की आईडी के साथ कोई आइटम नहीं हैं या एक से अधिक हैं, तो यह अपवाद फेंक देगा।)
MyModel.objects.get(pk=4)
सभी मॉडल ऑब्जेक्ट:
MyModel.objects.all()
मॉडल ऑब्जेक्ट्स में flag
सेट है जो True
:
MyModel.objects.filter(flag=True)
25 से अधिक एक model_num
मॉडल ऑब्जेक्ट:
MyModel.objects.filter(model_num__gt=25)
मॉडल के साथ वस्तुओं name
"सस्ते आइटम" और के flag
को सेट False
:
MyModel.objects.filter(name="Cheap Item", flag=False)
विशिष्ट स्ट्रिंग के लिए सरल खोज name
(केस-संवेदी):
MyModel.objects.filter(name__contains="ch")
विशिष्ट स्ट्रिंग के लिए मॉडल सरल खोज name
(केस-असंवेदनशील):
MyModel.objects.filter(name__icontains="ch")
क्यू वस्तुओं के साथ उन्नत प्रश्न
मॉडल दिया:
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
हम आपकी खोज क्वेरी में AND
, OR
स्थितियां बनाने के लिए Q
ऑब्जेक्ट का उपयोग कर सकते हैं। उदाहरण के लिए, model_num>15
कि हम सभी वस्तुओं को चाहते हैं जिनके पास flag=True
OR model_num>15
।
from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15))
उपरोक्त अनुवाद WHERE flag=True OR model_num > 15
इसी तरह एक और आप क्या करेंगे।
MyModel.objects.filter(Q(flag=True) & Q(model_num__gt=15))
Q
ऑब्जेक्ट हमें ~
के उपयोग के साथ नहीं प्रश्न बनाने की अनुमति देते हैं। मान लें कि हम सभी वस्तुओं को प्राप्त करना चाहते हैं जिनके पास flag=False
और model_num!=15
, हम करेंगे:
MyModel.objects.filter(Q(flag=True) & ~Q(model_num=15))
यदि filter()
में क्यू ऑब्जेक्ट्स और "सामान्य" पैरामीटर का उपयोग किया जाता है, तो Q
ऑब्जेक्ट्स को पहले आना चाहिए। के साथ मॉडल के लिए निम्न क्वेरी खोज ( flag
करने के लिए सेट True
या की तुलना में एक मॉडल संख्या अधिक से अधिक 15
) और एक ऐसा नाम है 'एच' के साथ शुरू होता है।
from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15), name__startswith="H")
नोट: Q
ऑब्जेक्ट्स को किसी भी लुकअप फंक्शन के साथ उपयोग किया जा सकता है जो कि कीवर्ड तर्क जैसे कि filter
, exclude
, get
। सुनिश्चित करें कि जब आप उपयोग करते get
कि आप केवल एक वस्तु वापस करेंगे या MultipleObjectsReturned
ऑब्जेक्ट्स को छोड़ दिया जाएगा, तो अपवाद उठाया जाएगा।
ManyToManyField (n + 1 अंक) पर प्रश्नों की संख्या कम करें
मुसीबत
# models.py:
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
class Book(models.Model):
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.all()
# Query the database on each iteration (len(author) times)
# if there is 100 librairies, there will have 100 queries plus the initial query
for library in libraries:
books = library.books.all()
books[0].title
# ...
# total : 101 queries
समाधान
उपयोग prefetch_related
पर ManyToManyField
यदि आप जानते हैं कि आप का उपयोग करने के बाद एक क्षेत्र है जो एक है की आवश्यकता होगी ManyToManyField
क्षेत्र।
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
# Does not query the database again, since `books` is pre-populated
for library in libraries:
books = library.books.all()
books[0].title
# ...
# total : 2 queries - 1 for libraries, 1 for books
prefetch_related
उपयोग लुकअप फ़ील्ड पर भी किया जा सकता है:
# models.py:
class User(models.Model):
name = models.CharField(max_length=100)
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
class Book(models.Model):
title = models.CharField(max_length=100)
readers = models.ManyToManyField(User)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books', 'books__readers').all()
# Does not query the database again, since `books` and `readers` is pre-populated
for library in libraries:
for book in library.books.all():
for user in book.readers.all():
user.name
# ...
# total : 3 queries - 1 for libraries, 1 for books, 1 for readers
हालाँकि, एक बार क्वेरीसेट निष्पादित हो जाने के बाद, प्राप्त किए गए डेटा को फिर से डेटाबेस से टकराने के बिना बदला नहीं जा सकता है। निम्नलिखित उदाहरण के लिए अतिरिक्त प्रश्नों को निष्पादित करेगा:
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
for library in libraries:
for book in library.books.filter(title__contains="Django"):
print(book.name)
Django 1.7 में पेश की गई Prefetch
ऑब्जेक्ट का उपयोग करके निम्नलिखित को अनुकूलित किया जा सकता है:
from django.db.models import Prefetch
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related(
Prefetch('books', queryset=Book.objects.filter(title__contains="Django")
).all()
for library in libraries:
for book in library.books.all():
print(book.name) # Will print only books containing Django for each library
फॉरेनके फील्ड पर प्रश्नों की संख्या कम करें (n + 1 अंक)
मुसीबत
Django क्वेरीज़ का मूल्यांकन एक आलसी फैशन में किया जाता है। उदाहरण के लिए:
# models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database
books = Book.objects.all()
for book in books:
# Query the database on each iteration to get author (len(books) times)
# if there is 100 books, there will have 100 queries plus the initial query
book.author
# ...
# total : 101 queries
उपरोक्त कोड प्रत्येक पुस्तक के लेखक के लिए डेटाबेस को क्वेरी करने के लिए django का कारण बनता है। यह अक्षम है, और केवल एक ही क्वेरी करना बेहतर है।
समाधान
यदि आप जानते हैं कि आपको बाद में एक ForeignKey
फ़ील्ड का उपयोग करने की आवश्यकता होगी, तो ForeignKey
पर select_related
उपयोग करें।
# views.py
def myview(request):
# Query the database.
books = Books.objects.select_related('author').all()
for book in books:
# Does not query the database again, since `author` is pre-populated
book.author
# ...
# total : 1 query
लुकअप फ़ील्ड पर select_related
का भी उपयोग किया जा सकता है:
# models.py:
class AuthorProfile(models.Model):
city = models.CharField(max_length=100)
class Author(models.Model):
name = models.CharField(max_length=100)
profile = models.OneToOneField(AuthorProfile)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
books = Book.objects.select_related('author')\
.select_related('author__profile').all()
for book in books:
# Does not query database
book.author.name
# or
book.author.profile.city
# ...
# total : 1 query
Django क्वेरीसेट के लिए SQL प्राप्त करें
क्वेरीसेट पर query
विशेषता आपको आपकी क्वेरी के लिए SQL समकक्ष सिंटैक्स देती है।
>>> queryset = MyModel.objects.all()
>>> print(queryset.query)
SELECT "myapp_mymodel"."id", ... FROM "myapp_mymodel"
चेतावनी:
यह आउटपुट केवल डीबगिंग उद्देश्यों के लिए उपयोग किया जाना चाहिए। उत्पन्न क्वेरी बैकएंड-विशिष्ट नहीं है। जैसे, पैरामीटर ठीक से उद्धृत नहीं किए जाते हैं, जिससे यह SQL इंजेक्शन के लिए असुरक्षित हो जाता है, और क्वेरी आपके डेटाबेस बैकएंड पर निष्पादन योग्य भी नहीं हो सकती है।
QuerySet से पहला और अंतिम रिकॉर्ड प्राप्त करें
पहली वस्तु प्राप्त करने के लिए:
MyModel.objects.first()
अंतिम वस्तु प्राप्त करने के लिए:
MyModel.objects.last()
फ़िल्टर पहली वस्तु का उपयोग करना:
MyModel.objects.filter(name='simple').first()
फ़िल्टर का उपयोग अंतिम वस्तु:
MyModel.objects.filter(name='simple').last()
एफ ऑब्जेक्ट्स के साथ उन्नत क्वेरी
एक एफ () ऑब्जेक्ट एक मॉडल फ़ील्ड या एनोटेट कॉलम के मूल्य का प्रतिनिधित्व करता है। यह वास्तव में उन्हें पायथन मेमोरी में डेटाबेस से बाहर खींचने के लिए बिना मॉडल फ़ील्ड मानों को संदर्भित करना और उनका उपयोग करके डेटाबेस संचालन करना संभव बनाता है। - एफ () भाव
जब भी आपको अपनी क्वेरी में किसी अन्य फ़ील्ड के मान को संदर्भित करने की आवश्यकता हो, तो F()
ऑब्जेक्ट का उपयोग करना उचित है। अपने आप से, F()
ऑब्जेक्ट्स का कोई मतलब नहीं है, और उन्हें क्वेरीसेट के बाहर नहीं बुलाया जाना चाहिए और नहीं होना चाहिए। उनका उपयोग उसी क्वेरी पर फ़ील्ड के मान को संदर्भित करने के लिए किया जाता है।
उदाहरण के लिए, एक मॉडल दिया ...
SomeModel(models.Model):
...
some_field = models.IntegerField()
... एक उपयोगकर्ता कर सकते हैं क्वेरी वस्तुओं जहां some_field
मूल्य दो बार अपनी है id
द्वारा संदर्भित id
फ़ील्ड का मान का उपयोग कर छानने, जबकि F()
इस तरह:
SomeModel.objects.filter(some_field=F('id') * 2)
F('id')
केवल उसी उदाहरण के लिए id
मान को संदर्भित करता है। Django इसका उपयोग इसी SQL स्टेटमेंट को बनाने के लिए करता है। इस मामले में कुछ निकटता से:
SELECT * FROM some_app_some_model
WHERE some_field = ((id * 2))
F()
अभिव्यक्तियों के बिना यह या तो कच्चे एसक्यूएल के साथ या पायथन में फ़िल्टरिंग के साथ पूरा किया जाएगा (जो विशेष रूप से प्रदर्शन को कम करता है जब बहुत सारी वस्तुएं होती हैं)।
संदर्भ:
F()
वर्ग परिभाषा:
मौजूदा क्वेरी ऑब्जेक्ट के संदर्भों को हल करने में सक्षम ऑब्जेक्ट। - एफ स्रोत
नोट: पोस्ट किया गया यह उदाहरण TinyInstance की सहमति से ऊपर सूचीबद्ध उत्तर से आया है।