Django में कई तर्कों और चेन फिल्टर के साथ फिल्टर के बीच अंतर क्या है?
Django में कई तर्कों और चेन फिल्टर के साथ फिल्टर के बीच अंतर क्या है?
जवाबों:
जैसा कि आप उत्पन्न SQL कथनों में देख सकते हैं कि अंतर "OR" नहीं है क्योंकि कुछ पर संदेह हो सकता है। यह कैसे WHERE और JOIN रखा गया है।
उदाहरण 1 (उसी तालिका में शामिल हुए): https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships से
Blog.objects.filter(
entry__headline__contains='Lennon',
entry__pub_date__year=2008)
इससे आपको उन सभी ब्लॉग्स मिल जाएंगे जिनमें दोनों के साथ एक प्रविष्टि है (entry__headline__contains='Lennon') AND (entry__pub_date__year=2008)
, जो कि आप इस क्वेरी से उम्मीद करेंगे।
परिणाम:
Blog with {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
उदाहरण 2 (जंजीर)
Blog.objects.filter(
entry__headline__contains='Lennon'
).filter(
entry__pub_date__year=2008)
यह उदाहरण 1 से सभी परिणामों को कवर करेगा, लेकिन यह थोड़ा और परिणाम उत्पन्न करेगा। क्योंकि यह पहले सभी ब्लॉग को फ़िल्टर करता है (entry__headline__contains='Lennon')
और फिर परिणाम फ़िल्टर से (entry__pub_date__year=2008)
।
अंतर यह है कि यह आपको परिणाम भी देगा जैसे:
एकाधिक प्रविष्टियों के साथ एक एकल ब्लॉग
{entry.headline: '**Lennon**', entry.pub_date: 2000},
{entry.headline: 'Bill', entry.pub_date: **2008**}
जब पहली फ़िल्टर का मूल्यांकन किया गया था तो पहली प्रविष्टि (भले ही इसमें अन्य प्रविष्टियाँ हों जो मेल नहीं खाती हैं) के कारण पुस्तक शामिल है। जब दूसरे फ़िल्टर का मूल्यांकन किया जाता है तो पुस्तक को दूसरी प्रविष्टि के कारण शामिल किया जाता है।
एक तालिका: लेकिन यदि क्वेरी में युजी और डीटीइंग से उदाहरण जैसी तालिकाओं को शामिल नहीं किया गया है। परिणाम वही है।
(entry__headline__contains='Lennon')
और फिर परिणाम फिल्टरों से (entry__pub_date__year=2008)
" यदि "फिर" परिणाम से "सटीक होता है, तो यह कुछ के साथ क्यों शामिल होगा entry.headline == 'Bill'
.. .wouldn't entry__headline__contains='Lennon'
बाहर फिल्टर Bill
उदाहरण?
वह मामला जिसमें "कई तर्क फ़िल्टर-क्वेरी" के परिणाम "जंजीर-फ़िल्टर-क्वेरी" से भिन्न होते हैं, निम्नलिखित हैं:
संदर्भित वस्तुओं के आधार पर संदर्भित वस्तुओं का चयन करना और संबंध एक-से-कई (या कई-से-कई) हैं।
कई फिल्टर:
Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^
जंजीर फिल्टर:
Referenced.filter(referencing1_a=x).filter(referencing1_b=y)
दोनों प्रश्न अलग-अलग परिणाम उत्पन्न कर सकते हैं:
यदि अधिक है तो संदर्भित-मॉडल मेंReferencing1
एक पंक्ति संदर्भित-मॉडल में एक ही पंक्ति को संदर्भित कर सकती हैReferenced
। यह मामला हो सकता हैReferenced
:Referencing1
या तो 1: एन (एक से कई) या एन: एम (कई से कई) संबंध-जहाज हैं।
उदाहरण:
गौर करें कि मेरे आवेदन my_company
में दो मॉडल हैं Employee
और Dependent
। एक कर्मचारी my_company
आश्रितों से अधिक हो सकता है (दूसरे शब्दों में एक आश्रित एक एकल कर्मचारी का बेटा / बेटी हो सकता है, जबकि एक कर्मचारी के एक से अधिक बेटे / बेटी हो सकते हैं)।
एह, पति-पत्नी की तरह मान लेना दोनों में काम नहीं कर सकते my_company
। मैंने 1: m उदाहरण लिया
तो, Employee
संदर्भित-मॉडल जिसे अधिक संदर्भित किया जा सकता है तो Dependent
वह संदर्भ-मॉडल है। अब संबंध-स्थिति पर विचार करें:
Employee: Dependent: +------+ +------+--------+-------------+--------------+ | name | | name | E-name | school_mark | college_mark | +------+ +------+--------+-------------+--------------+ | A | | a1 | A | 79 | 81 | | B | | b1 | B | 80 | 60 | +------+ | b2 | B | 68 | 86 | +------+--------+-------------+--------------+
आश्रित
a1
कर्मचारी को संदर्भित करता हैA
, और आश्रितb1, b2
कर्मचारी के लिए संदर्भB
।
अब मेरी क्वेरी है:
उन सभी कर्मचारियों का पता लगाएं, जिनके बेटे / बेटी के कॉलेज और स्कूल दोनों में अंतर के निशान (=> 75%) हैं?
>>> Employee.objects.filter(dependent__school_mark__gte=75,
... dependent__college_mark__gte=75)
[<Employee: A>]
आउटपुट 'ए' डिपेंडेंट 'ए 1' है, जिसमें कॉलेज और स्कूल दोनों में अंतर है, कर्मचारी 'ए' पर निर्भर है। नोट 'B' इसलिए नहीं चुना गया है क्योंकि 'B' के बच्चे के nether में कॉलेज और स्कूल दोनों में भेद के निशान हैं। संबंधपरक बीजगणित:
कर्मचारी ⋈ (school_mark> = 75 और college_mark> = 75) आश्रित
दूसरे मामले में, मुझे एक प्रश्न चाहिए:
उन सभी कर्मचारियों को खोजें जिनके कुछ आश्रितों के कॉलेज और स्कूल में भेद के निशान हैं?
>>> Employee.objects.filter(
... dependent__school_mark__gte=75
... ).filter(
... dependent__college_mark__gte=75)
[<Employee: A>, <Employee: B>]
इस बार 'बी' का चयन इसलिए भी किया गया क्योंकि 'बी' के दो बच्चे हैं (एक से अधिक!), एक का स्कूल 'बी 1' में अंतर है और दूसरे का कॉलेज 'बी 2' में भी अंतर है।
फ़िल्टर के आदेश से कोई फर्क नहीं पड़ता कि हम क्वेरी के ऊपर भी लिख सकते हैं:
>>> Employee.objects.filter(
... dependent__college_mark__gte=75
... ).filter(
... dependent__school_mark__gte=75)
[<Employee: A>, <Employee: B>]
परिणाम वही है! संबंधपरक बीजगणित हो सकता है:
(कर्मचारी Emp (school_mark> = 75) आश्रित) _ (college_mark> = 75) आश्रित
निम्नलिखित नोट करें:
dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75)
dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75)
समान परिणाम: [<Dependent: a1>]
मैं टारगेट SQL क्वेरी का उपयोग करके Django द्वारा उत्पन्न किया गया है print qd1.query
और print qd2.query
दोनों समान हैं (Django 1.6)।
लेकिन शब्दार्थ दोनों मेरे लिए अलग हैं । पहला साधारण खंड जैसा दिखता है mark [school_mark> = 75 और college_mark> = 75] (आश्रित) और दूसरा धीमा नेस्टेड क्वेरी की तरह: σ [school_mark> = 75] (σ [college_mark> = 75] (आश्रित))।
यदि किसी को कोड @ कोडपैड की आवश्यकता है
btw, यह दस्तावेज़ीकरण में दिया गया है @ बहु-मूल्यवान रिश्तों को मैंने अभी एक उदाहरण जोड़ा है, मुझे लगता है कि यह किसी नए व्यक्ति के लिए उपयोगी होगा।
अधिकांश समय, क्वेरी के लिए परिणामों का एक ही संभव सेट होता है।
जब आप एम 2 एम के साथ काम कर रहे हों तो चेनिंग फिल्टर का उपयोग होता है:
इस पर विचार करो:
# will return all Model with m2m field 1
Model.objects.filter(m2m_field=1)
# will return Model with both 1 AND 2
Model.objects.filter(m2m_field=1).filter(m2m_field=2)
# this will NOT work
Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2))
अन्य उदाहरणों का स्वागत है।
प्रदर्शन अंतर बहुत बड़ा है। यह कोशिश करो और देखो।
Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)
की तुलना में आश्चर्यजनक रूप से धीमा है
Model.objects.filter(condition_a, condition_b, condition_c)
जैसा कि प्रभावी Django ORM में उल्लेख किया गया है ,
- QuerySets स्मृति में स्थिति बनाए रखता है
- चेनिंग क्लोनिंग को ट्रिगर करता है, उस स्थिति को दोहराता है
- दुर्भाग्य से, QuerySets बहुत सारे राज्य बनाए रखता है
- यदि संभव हो, तो एक से अधिक फ़िल्टर न करें
तुलना करने के लिए कच्चे sql प्रश्नों को देखने के लिए आप कनेक्शन मॉड्यूल का उपयोग कर सकते हैं। जैसा कि युजी द्वारा समझाया गया है, अधिकांश भाग के लिए वे समकक्ष हैं जैसा कि यहां दिखाया गया है:
>>> from django.db import connection
>>> samples1 = Unit.objects.filter(color="orange", volume=None)
>>> samples2 = Unit.objects.filter(color="orange").filter(volume=None)
>>> list(samples1)
[]
>>> list(samples2)
[]
>>> for q in connection.queries:
... print q['sql']
...
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
>>>
यह उत्तर Django 3.1 पर आधारित है।
वातावरण
मॉडल
class Blog(models.Model):
blog_id = models.CharField()
class Post(models.Model):
blog_id = models.ForeignKeyField(Blog)
title = models.CharField()
pub_year = models.CharField() # Don't use CharField for date in production =]
डेटाबेस तालिकाओं
फिल्टर बुलाते हैं
Blog.objects.filter(post__title="Title A", post__pub_year="2020")
# Result: <QuerySet [<Blog: 1>]>
Blog.objects.filter(post__title="Title A").filter(post_pub_date="2020)
# Result: <QuerySet [<Blog: 1>, [<Blog: 2>]>
व्याख्या
इससे पहले कि मैं आगे कुछ भी शुरू करूं, मुझे ध्यान देना होगा कि यह उत्तर उन परिस्थितियों पर आधारित है जो ऑब्जेक्ट्स को फ़िल्टर करने के लिए "ManyToManyField" या रिवर्स "ForeignKey" का उपयोग करती हैं।
यदि आप वस्तुओं को फ़िल्टर करने के लिए एक ही तालिका या "OneToOneField" का उपयोग कर रहे हैं, तो "एकाधिक तर्क फ़िल्टर" या "फ़िल्टर-श्रृंखला" का उपयोग करने के बीच कोई अंतर नहीं होगा। वे दोनों एक "और" शर्त फ़िल्टर की तरह काम करेंगे।
"एकाधिक तर्क फ़िल्टर" और "फ़िल्टर-श्रृंखला" का उपयोग करने के तरीके को समझने के लिए सीधे आगे का तरीका "ManyToManyField" या एक रिवर्स "ForeignKey" फ़िल्टर को याद रखना है, "एकाधिक तर्क फ़िल्टर" एक "और" स्थिति और "फ़िल्टर" है -चैन "एक" या "स्थिति है।
"एकाधिक तर्क फ़िल्टर" और "फ़िल्टर-श्रृंखला" को इतना अलग बनाने का कारण यह है कि वे अलग-अलग ज्वाइन टेबल से परिणाम प्राप्त करते हैं और क्वेरी स्टेटमेंट में विभिन्न स्थिति का उपयोग करते हैं।
"एकाधिक तर्क फ़िल्टर" "पोस्ट " का उपयोग करें । सार्वजनिक वर्ष की पहचान करने के लिए "Public_Year" = '2020'
SELECT *
FROM "Book"
INNER JOIN ("Post" ON "Book"."id" = "Post"."book_id")
WHERE "Post"."Title" = 'Title A'
AND "Post"."Public_Year" = '2020'
"फ़िल्टर-चेन" डेटाबेस क्वेरी "T1" का उपयोग करती है । सार्वजनिक वर्ष की पहचान करने के लिए "Public_Year" = '2020'
SELECT *
FROM "Book"
INNER JOIN "Post" ON ("Book"."id" = "Post"."book_id")
INNER JOIN "Post" T1 ON ("Book"."id" = "T1"."book_id")
WHERE "Post"."Title" = 'Title A'
AND "T1"."Public_Year" = '2020'
लेकिन अलग-अलग स्थितियां परिणाम को क्यों प्रभावित करती हैं?
मेरा मानना है कि हममें से ज्यादातर लोग, जो मेरे साथ इस पृष्ठ पर आते हैं =], पहले "मल्टीपल आर्ग्यूमेंट फ़िल्टर" और "फ़िल्टर-चेन" का उपयोग करते समय एक ही धारणा है।
जो हम मानते हैं कि परिणाम को एक तालिका से प्राप्त किया जाना चाहिए जैसे कि "एकाधिक तर्क फ़िल्टर" के लिए सही है। इसलिए यदि आप "एकाधिक तर्क फ़िल्टर" का उपयोग कर रहे हैं, तो आपको अपनी अपेक्षा के अनुसार परिणाम मिलेगा।
लेकिन "फ़िल्टर-चेन" के साथ काम करते समय, Django एक अलग क्वेरी स्टेटमेंट बनाता है जो उपरोक्त तालिका को निम्नलिखित में बदलता है। साथ ही, "सार्वजनिक वर्ष" को क्वेरी विवरण में परिवर्तन के कारण "पोस्ट" अनुभाग के बजाय "T1" अनुभाग के तहत पहचाना जाता है।
लेकिन यह अजीब "फिल्टर-चेन" टेबल आरेख में कहां से आता है?
मैं एक डेटाबेस विशेषज्ञ नहीं हूँ। नीचे दिए गए स्पष्टीकरण को मैंने डेटाबेस की समान संरचना बनाने के बाद अब तक समझा है और उसी क्वेरी स्टेटमेंट के साथ परीक्षण किया है।
निम्न आरेख दिखाएगा कि यह अजीब "फ़िल्टर-चेन" टेबल आरेख से कैसे जुड़ता है।
डेटाबेस पहले "ब्लॉग" और "पोस्ट" टेबल की पंक्ति को एक-एक करके मेल करके एक टेबल बना देगा।
उसके बाद, डेटाबेस अब उसी मिलान प्रक्रिया को फिर से करता है लेकिन "T1" तालिका से मिलान करने के लिए चरण 1 परिणाम तालिका का उपयोग करता है जो कि केवल समान "पोस्ट" तालिका है।
और इस तरह यह अजीब "फिल्टर-चेन" टेबल आरेख से जुड़ता है।
निष्कर्ष
तो दो चीजें "मल्टीपल अर्ग्युमेंट्स फिल्टर" और "फिल्टर-चेन" को अलग बनाती हैं।
यह याद रखने का गंदा तरीका कि इसका "मल्टीपल आर्ग्यूमेंट फ़िल्टर" कैसे उपयोग किया जाता है, एक "और" स्थिति है और "फ़िल्टर-चेन" एक "ORT" स्थिति है, जबकि एक "ManyToManyField" या रिवर्स "ForeignKey" फ़िल्टर है।
यदि आप इस पेज पर अंत में देख रहे हैं कि गतिशील रूप से कई चेनिंग फिल्टर के साथ django क्वेरी को कैसे बनाया जाए, लेकिन आपको AND
इसके बजाय फ़िल्टर की आवश्यकता होती है OR
, तो Q ऑब्जेक्ट का उपयोग करने पर विचार करें ।
एक उदाहरण:
# First filter by type.
filters = None
if param in CARS:
objects = app.models.Car.objects
filters = Q(tire=param)
elif param in PLANES:
objects = app.models.Plane.objects
filters = Q(wing=param)
# Now filter by location.
if location == 'France':
filters = filters & Q(quay=location)
elif location == 'England':
filters = filters & Q(harbor=location)
# Finally, generate the actual queryset
queryset = objects.filter(filters)
यदि एक और बी की आवश्यकता है
and_query_set = Model.objects.filter(a=a, b=b)
यदि आवश्यक हो तो b
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
आधिकारिक दस्तावेज: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
संबंधित पोस्ट: Django में कई फिल्टर () का पीछा करते हुए, यह एक बग है?
उदाहरण के लिए, जब आपके पास अपनी संबंधित वस्तु के लिए अनुरोध होता है, तो अंतर होता है
class Book(models.Model):
author = models.ForeignKey(Author)
name = models.ForeignKey(Region)
class Author(models.Model):
name = models.ForeignKey(Region)
निवेदन
Author.objects.filter(book_name='name1',book_name='name2')
खाली सेट देता है
और अनुरोध करें
Author.objects.filter(book_name='name1').filter(book_name='name2')
उन लेखकों को लौटाता है जिनके पास 'name1' और 'name2' दोनों की किताबें होती हैं
जानकारी के लिए https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships पर देखें
Author.objects.filter(book_name='name1',book_name='name2')
यह भी मान्य अजगर नहीं है, यह होगाSyntaxError: keyword argument repeated