2012-11-07 24 views
12

मैं इस तरह के एक बुक मॉडल है एक सूची में सभी वस्तुओं पर ManyToMany फिल्टर मिलानDjango: संक्षेप में</p> <pre><code>class Book(models.Model): authors = models.ManyToManyField(Author, ...) ... </code></pre> <p>:

मैं पुस्तकें जिनके लेखकों को कड़ाई से एक के बराबर हैं पुनः प्राप्त करना चाहते हैं लेखकों का दिया गया सेट। मुझे यकीन नहीं है कि एक ऐसी क्वेरी है जो यह करती है, लेकिन कोई सुझाव उपयोगी होगा।

लंबे में:

यहाँ मैं क्या करने की कोशिश की है,

# A sample set of authors 
target_authors = set((author_1, author_2)) 

# To reduce the search space, 
# first retrieve those books with just 2 authors. 
candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors)) 

final_books = QuerySet() 
for author in target_authors: 
    temp_books = candidate_books.filter(authors__in=[author]) 
    final_books = final_books and temp_books 

(है कि एक AttributeError हो रही चलाने के लिए विफल) ... और यहाँ है कि मैं क्या मिला:

AttributeError: 'NoneType' object has no attribute '_meta' 

आम तौर पर, मुझे इस समस्या के साथ एक मॉडल से कैसे पूछना चाहिए कि इसके कई क्षेत्रों में दिए गए ऑब्जेक्ट्स का एक सेट मेरे मामले में है?

ps: मुझे कुछ प्रासंगिक SO प्रश्न मिले लेकिन स्पष्ट उत्तर नहीं मिला। कोई भी अच्छा सूचक भी सहायक होगा। धन्यवाद।

+0

लगभग वहां। इस प्रश्न में उत्तर देखें: http://stackoverflow.com/questions/8618068/django-filter-queryset-in-for-every-item-in-list –

उत्तर

12

@ goliney के दृष्टिकोण की तरह, मैं एक समाधान मिल गया। हालांकि, मुझे लगता है कि दक्षता में सुधार किया जा सकता है।

# A sample set of authors 
target_authors = set((author_1, author_2)) 

# To reduce the search space, first retrieve those books with just 2 authors. 
candidate_books = Book.objects.annotate(c=Count('authors')).filter(c=len(target_authors)) 

# In each iteration, we filter out those books which don't contain one of the 
# required authors - the instance on the iteration. 
for author in target_authors: 
    candidate_books = candidate_books.filter(authors=author) 

final_books = candidate_books 
+0

आपके समाधान वही करते हैं। फ़िल्टर kwargs हैं "AND" ed –

+0

आप सही हैं, वे वही दिखते हैं। हालांकि, मुझे लगता है कि एक निष्पादन अंतर है। जहां तक ​​मैं समझ गया, आपके दृष्टिकोण में, 'लेखक 'फ़ील्ड में' लेखक 'जो' लेखक_1 'से मेल खाता है, को भी' author_2 'से मिलान करने की उम्मीद है। दूसरी ओर, पुनरावर्तक फ़िल्टरिंग ऐसी बाधा को लागू नहीं करती है। अगर मैं गलत हूं, तो कृपया मुझे सही करें। मैं सीखने के लिए यहाँ हूँ। एक बार फिर धन्यवाद! – iuysal

+0

खोज स्थान को कम करने के विचार पर अच्छा बिंदु। वोट दें! –

3

आप उपयोग कर सकते हैं complex lookups with Q objects

from django.db.models import Q 
... 
target_authors = set((author_1, author_2)) 
q = Q() 
for author in target_authors: 
    q &= Q(authors=author) 
Books.objects.annotate(c=Count('authors')).filter(c=len(target_authors)).filter(q) 
+3

धन्यवाद @ goliney, हालांकि दृष्टिकोण साफ और प्रेरक है, मैं अनुमान लगाओ कि मैं जो कर रहा हूं वह नहीं कर रहा है। यदि केवल एक लेखक है, तो यह ठीक काम करता है, लेकिन जब कई लेखक होते हैं, और प्रक्रिया संभवतः एक असंभव बाधा उत्पन्न करती है (जहां एक = x और a = y)। – iuysal

+2

जैसा कि यह निकला, मेरे लिए क्यू() व्यवहार में कुछ अस्पष्ट है। [इस सापेक्ष प्रश्न] के अनुसार (http://stackoverflow.com/a/5542966/1065780) मुझे एसओ, 'क्यू() और क्यू() 'पर मिलता है' .filter() के बराबर नहीं है। फ़िल्टर() ' । आपके प्रश्न के लिए धन्यवाद –

+2

लिंक के लिए धन्यवाद और अपना समय साझा करें। – iuysal

0

मैं एक ही समस्या में आए और iuysal रूप में एक ही निष्कर्ष पर पहुंचा, तक मैं एक मध्यम आकार खोज करने के लिए (150 1000 रिकॉर्ड फिल्टर के साथ मेरा अनुरोध टाइम आउट होता है) था।

मेरे विशेष मामले में खोज के परिणामस्वरूप कोई रिकॉर्ड नहीं होगा क्योंकि एक रिकॉर्ड सभी 150 फ़िल्टरों के साथ संरेखित होगा, यह बहुत दुर्लभ है, आप यह सत्यापित करके प्रदर्शन समस्याओं के आसपास हो सकते हैं कि आवेदन करने से पहले QuerySet में रिकॉर्ड्स हैं समय बचाने के लिए और अधिक फिल्टर।

# In each iteration, we filter out those books which don't contain one of the 
# required authors - the instance on the iteration. 
for author in target_authors: 
    if candidate_books.count() > 0: 
     candidate_books = candidate_books.filter(authors=author) 

किसी कारण से Django खाली QuerySets पर फ़िल्टर लागू करता है। लेकिन यदि ऑप्टिमाइज़ेशन सही ढंग से लागू किया जाना है, तो तैयार क्वेरीसेट और सही ढंग से लागू इंडेक्स का उपयोग करना आवश्यक है।