Django में गतिशील रूप से OR क्वेरी फ़िल्टर कैसे लिखें?


104

एक उदाहरण से आप कई या क्वेरी फ़िल्टर देख सकते हैं:

Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

उदाहरण के लिए, इस परिणाम में:

[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]

हालाँकि, मैं इस क्वेरी फ़िल्टर को एक सूची से बनाना चाहता हूँ। उसको कैसे करे?

जैसे [1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))


1
आप इसे दो बार पूछ चुके हैं: stackoverflow.com/questions/852404
डोमिनिक रॉजर

इस विशिष्ट उपयोग के मामले के लिए आप शायद Article.objects.filter(pk__in=[1, 2, 3])आधुनिक django में उपयोग करेंगे , लेकिन यह सवाल अभी भी प्रासंगिक है कि क्या आप OR Qing ऑब्जेक्ट्स को एक साथ कुछ अधिक उन्नत करना चाहते हैं।
बेरिक

जवाबों:


162

आप अपने प्रश्नों की श्रृंखला इस प्रकार से कर सकते हैं:

values = [1,2,3]

# Turn list of values into list of Q objects
queries = [Q(pk=value) for value in values]

# Take one Q object from the list
query = queries.pop()

# Or the Q object with the ones remaining in the list
for item in queries:
    query |= item

# Query the model
Article.objects.filter(query)

3
धन्यवाद! यह वही था जो मैं खोज रहा था :) क्या आपको पता नहीं था कि आप = =
जैक हा

23
आप क्वेरी का उपयोग करके भी आरंभ कर सकते हैं: क्वेरी = क्यू ()
चचन

5
आप ** {'फ़ील्डनाम': मान} का उपयोग करके डायनामिक फ़ील्ड बना सकते हैं: क्वेरीज़ = [क्यू (** {'फ़ील्डनाम': वैल्यू) वैल्यू में वैल्यू के लिए]
रीची

1
यदि आप ऊपर जैसी वैकल्पिक शर्तें जोड़ना चाहते हैं, तो आप Django के साथ कच्चे प्रश्नों की रचना कैसे कर सकते हैं?
उपयोगकर्ता

यह मेरे लिए काम नहीं किया, मुझे पता नहीं क्यों। प्रश्न मेरे लिए शून्य परिणाम लौटाते हैं
मेहरान नूरी

83

अधिक जटिल प्रश्नों के निर्माण के लिए Q () ऑब्जेक्ट के स्थिरांक Q.OR और Q.AND में एक साथ जोड़ने का उपयोग करने का विकल्प है (जैसे विधि)

list = [1, 2, 3]
# it gets a bit more complicated if we want to dynamically build
# OR queries with dynamic/unknown db field keys, let's say with a list
# of db fields that can change like the following
# list_with_strings = ['dbfield1', 'dbfield2', 'dbfield3']

# init our q objects variable to use .add() on it
q_objects = Q(id__in=[])

# loop trough the list and create an OR condition for each item
for item in list:
    q_objects.add(Q(pk=item), Q.OR)
    # for our list_with_strings we can do the following
    # q_objects.add(Q(**{item: 1}), Q.OR)

queryset = Article.objects.filter(q_objects)

# sometimes the following is helpful for debugging (returns the SQL statement)
# print queryset.query

12
इस थ्रेड के नए लोगों के लिए, मेरी तरह, मुझे लगता है कि इस उत्तर को शीर्ष उत्तर माना जाना चाहिए। यह स्वीकृत उत्तर की तुलना में अधिक Djangoesque है। धन्यवाद!
थेरेसान्ना

5
मैं इस बात पर बहस करूंगा कि यह बिलियन OR और AND ऑपरेटरों ((और &)) का उपयोग करने के लिए अधिक पायथोनिक है। q_objects |= Q(pk=item)
बोबोर्ट

उत्तम! धन्यवाद!
आरएल श्याम

1
ध्यान देने योग्य है कि अगर listखाली होना होता है तो आप इसके बराबर लौटेंगे Article.objects.all()Article.objects.none()हालांकि उस टेस्ट के लिए वापसी करके इसे कम करना आसान है ।
विल

2
@ आप के q_objectsसाथ भी शुरू कर सकते हैं Q(id__in=[])। यह हमेशा विफल रहेगा जब तक कि किसी चीज के साथ ओरेड न हो और क्वेरी ऑप्टिमाइज़र इसे अच्छी तरह से संभाल लेगा।
जोनाथन रिचर्ड्स

44

अजगर के कम फ़ंक्शन का उपयोग करके डेव वेब के जवाब लिखने का एक छोटा तरीका :

# For Python 3 only
from functools import reduce

values = [1,2,3]

# Turn list of values into one big Q objects  
query = reduce(lambda q,value: q|Q(pk=value), values, Q())  

# Query the model  
Article.objects.filter(query)  

ऐसा लगता है कि "बिलिन" कम को हटा दिया गया था और इसके साथ बदल दिया गया था functools.reduceस्रोत
lsowen

धन्यवाद @lsowen, फिक्स्ड
टॉम विनर

और operator.or_लैम्ब्डा के बजाय इसका उपयोग करना संभव है ।
ईजीनिन

38
from functools import reduce
from operator import or_
from django.db.models import Q

values = [1, 2, 3]
query = reduce(or_, (Q(pk=x) for x in values))

ठीक है, लेकिन कहाँ से operatorआया है?
mpiskore

1
@ चैंपियन: हर दूसरे पायथन मॉड्यूल के समान स्थान: आप इसे आयात करते हैं।
इग्नासियो वाज़क्वेज़-अब्राम्स

1
मजेदार। यह वास्तव में मेरा सवाल था: मैं इसे किस मॉड्यूल / पुस्तकालय में पा सकता हूं? Google ने बहुत मदद नहीं की।
मपिसकौर

ओह, मुझे लगा कि यह कुछ प्रकार के Django ORM ऑपरेटर है। कितनी मूर्खता है मेरी, धन्यवाद!
मपिसकौर

20

शायद sql IN स्टेटमेंट का उपयोग करना बेहतर है।

Article.objects.filter(id__in=[1, 2, 3])

क्वेरी एपीआई संदर्भ देखें

यदि आपको वास्तव में गतिशील तर्क के साथ प्रश्न बनाने की आवश्यकता है, तो आप ऐसा कुछ कर सकते हैं (बदसूरत + परीक्षण नहीं):

query = Q(field=1)
for cond in (2, 3):
    query = query | Q(field=cond)
Article.objects.filter(query)

1
आप यह भी इस्तेमाल कर सकते हैंquery |= Q(field=cond)
Bobort

8

डॉक्स देखें :

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}

ध्यान दें कि यह विधि केवल प्राथमिक कुंजी लुकअप के लिए काम करती है, लेकिन लगता है कि आप क्या करने की कोशिश कर रहे हैं।

तो आप क्या चाहते हैं:

Article.objects.in_bulk([1, 2, 3])

6

मामले में हम प्रोग्राम करना चाहते हैं कि हम किस db क्षेत्र को क्वेरी करना चाहते हैं:

import operator
questions = [('question__contains', 'test'), ('question__gt', 23 )]
q_list = [Q(x) for x in questions]
Poll.objects.filter(reduce(operator.or_, q_list))

6

समाधान जो उपयोग करते हैं reduceऔर or_ऑपरेटरों को खेतों से फ़िल्टर करने के लिए गुणा करते हैं।

from functools import reduce
from operator import or_
from django.db.models import Q

filters = {'field1': [1, 2], 'field2': ['value', 'other_value']}

qs = Article.objects.filter(
   reduce(or_, (Q(**{f'{k}__in': v}) for k, v in filters.items()))
)

ps fएक नया प्रारूप है जो शाब्दिक है। इसे अजगर 3.6 में पेश किया गया था


4

आप प्रोग्राम को Q ऑब्जेक्ट का उपयोग करके किसी क्वेरी को प्रोग्रामेटिक रूप से अपडेट करने के लिए उपयोग कर सकते हैं।


2
क्या यह कहीं भी प्रलेखित है? मैं पिछले 15 मिनट से खोज रहा हूं, और यही एक चीज है जो मैं पा सकता हूं।
wobbily_col

हमारे उद्योग में बहुत पसंद है, यह StackOverflow पर प्रलेखित है!
क्रिस

2

यह गतिशील पीके सूची के लिए है:

pk_list = qs.values_list('pk', flat=True)  # i.e [] or [1, 2, 3]

if len(pk_list) == 0:
    Article.objects.none()

else:
    q = None
    for pk in pk_list:
        if q is None:
            q = Q(pk=pk)
        else:
            q = q | Q(pk=pk)

    Article.objects.filter(q)

आप q = Q()इसके बजाय उपयोग कर सकते हैं q = None, फिर if q is Noneक्लॉज को हटा सकते हैं - थोड़ा कम कुशल लेकिन कोड की तीन पंक्तियों को हटा सकते हैं। (खाली क्यू को बाद में क्वेरी चलाने पर मर्ज कर दिया जाता है।)
क्रिस

1

एक अन्य विकल्प मैं हाल ही में जब तक के बारे में पता नहीं था - QuerySetयह भी ओवरराइड करता है &, |, ~, आदि, ऑपरेटरों। अन्य प्रश्न जो कि या क्यू ऑब्जेक्ट इस प्रश्न का एक बेहतर समाधान है, लेकिन ब्याज / तर्क के लिए, आप यह कर सकते हैं:

id_list = [1, 2, 3]
q = Article.objects.filter(pk=id_list[0])
for i in id_list[1:]:
    q |= Article.objects.filter(pk=i)

str(q.query)WHEREक्लॉज के सभी फ़िल्टर के साथ एक क्वेरी लौटाएगा ।


1

पाश के लिए:

values = [1, 2, 3]
q = Q(pk__in=[]) # generic "always false" value
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)

कम करना:

from functools import reduce
from operator import or_

values = [1, 2, 3]
q_objects = [Q(pk=val) for val in values]
q = reduce(or_, q_objects, Q(pk__in=[]))
Article.objects.filter(q)

ये दोनों बराबर हैं Article.objects.filter(pk__in=values)

यह विचार करना महत्वपूर्ण है कि valuesखाली होने पर आप क्या चाहते हैं । Q()शुरुआती मूल्य के रूप में कई उत्तर सब कुछ वापस कर देंगे । Q(pk__in=[])एक बेहतर शुरुआती मूल्य है। यह एक हमेशा विफल रहने वाली वस्तु है जिसे ऑप्टिमाइज़र (यहां तक ​​कि जटिल समीकरणों के लिए) द्वारा अच्छी तरह से नियंत्रित किया जाता है।

Article.objects.filter(Q(pk__in=[]))  # doesn't hit DB
Article.objects.filter(Q(pk=None))    # hits DB and returns nothing
Article.objects.none()                # doesn't hit DB
Article.objects.filter(Q())           # returns everything

यदि आप खाली होने पर सब कुछ वापस करना चाहते हैंvalues , तो आपको ~Q(pk__in=[])उस व्यवहार को सुनिश्चित करना चाहिए :

values = []
q = Q()
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # only Tolkien

q &= ~Q(pk__in=[])
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # everything

यह याद रखना महत्वपूर्ण है कि महत्वपूर्ण है Q()है कुछ भी नहीं , नहीं हमेशा-सफल क्यू वस्तु। इसमें शामिल कोई भी ऑपरेशन इसे पूरी तरह से छोड़ देगा।


0

आसान ..
django.db.models से आयात करें Q आयात करें आप मॉडल args = (Q (दृश्यता = 1) - (Q (दृश्यता = 0) और Q (उपयोगकर्ता = self.user)) #Tuple पैरामीटर = {} #dear आदेश आयात करें = 'create_at' की सीमा = 10

Models.objects.filter(*args,**parameters).order_by(order)[:limit]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.