2012-04-05 16 views
26

मैं की तरह एक बुनियादी Django मॉडल है:Django Tastypie उन्नत छनन: क्यू के साथ जटिल लुकअप कैसे करना वस्तुओं

qset = (
    Q(name__icontains=query) | 
    Q(description__icontains=query) | 
    Q(email__icontains=query) 
    ) 
results = Business.objects.filter(qset).distinct() 
: मैं की तरह ऊपर मॉडल पर एक जटिल क्वेरी को निष्पादित करने की जरूरत है

class Business(models.Model): 
    name = models.CharField(max_length=200, unique=True) 
    email = models.EmailField() 
    phone = models.CharField(max_length=40, blank=True, null=True) 
    description = models.TextField(max_length=500) 

मैं कोशिश की है कोई भाग्य के साथ tastypie का उपयोग कर निम्न:

और tastypie के लिए वर्ग मेटा में मैं के रूप में स्थापित फ़िल्टरिंग:

filtering = { 
     'name: ALL, 
     'description': ALL, 
     'email': ALL, 
     'query': ['icontains',], 
    } 

मैं यह कैसे से निपटने कर सकते हैं करने के लिए कोई भी विचार?

धन्यवाद - न्यूटन

उत्तर

40

आप सही रास्ते पर हैं। हालांकि, build_filters को ओआरएम लुकअप में संसाधन लुकअप को स्थानांतरित करना माना जाता है।

डिफ़ॉल्ट कार्यान्वयन क्वेरी कीवर्ड को __ पर आधारित कुंजी_बिट्स, वैल्यू जोड़े में विभाजित करता है और फिर संसाधन के बीच मैपिंग और उसके ओआरएम समकक्ष के बीच मैपिंग खोजने का प्रयास करता है।

आपका कोड फ़िल्टर को लागू करने के लिए नहीं है, केवल इसे बनाएं।

def build_filters(self, filters=None): 
    if filters is None: 
     filters = {} 
    orm_filters = super(BusinessResource, self).build_filters(filters) 

    if('query' in filters): 
     query = filters['query'] 
     qset = (
       Q(name__icontains=query) | 
       Q(description__icontains=query) | 
       Q(email__icontains=query) 
       ) 
     orm_filters.update({'custom': qset}) 

    return orm_filters 

def apply_filters(self, request, applicable_filters): 
    if 'custom' in applicable_filters: 
     custom = applicable_filters.pop('custom') 
    else: 
     custom = None 

    semi_filtered = super(BusinessResource, self).apply_filters(request, applicable_filters) 

    return semi_filtered.filter(custom) if custom else semi_filtered 

क्योंकि आप क्यू वस्तुओं का उपयोग कर रहे, मानक apply_filters विधि बहुत चालाक अपना कस्टम फ़िल्टर कुंजी लागू करने के लिए (के बाद से कोई नहीं है) नहीं है, लेकिन आप जल्दी से इसे ओवरराइड और कर सकते हैं: यहाँ एक सुधार हुआ है और तय संस्करण है "कस्टम" नामक एक विशेष फ़िल्टर जोड़ें। ऐसा करने में आपका build_filters उपयुक्त फ़िल्टर ढूंढ सकता है, इसका अर्थ क्या है इसका उपयोग करें और इसे लागू करने के लिए कस्टम के रूप में पास करें। फ़िल्टर जो किसी आइटम के रूप में किसी शब्द से अपने मूल्य को अनपैक करने की कोशिश करने के बजाय इसे सीधे लागू करेगा।

Class MyResource(ModelResource): 

    def __init__(self, *args, **kwargs): 
    super(MyResource, self).__init__(*args, **kwargs) 
    self.q_filters = [] 

    def build_filters(self, filters=None): 
    orm_filters = super(MyResource, self).build_filters(filters) 

    q_filter_needed_1 = [] 
    if "what_im_sending_from_client" in filters: 
     if filters["what_im_sending_from_client"] == "my-constraint": 
     q_filter_needed_1.append("something to filter") 

    if q_filter_needed_1: 
     a_new_q_object = Q() 
     for item in q_filter_needed: 
     a_new_q_object = a_new_q_object & Q(filtering_DB_field__icontains=item) 
     self.q_filters.append(a_new_q_object) 

    def apply_filters(self, request, applicable_filters): 
    filtered = super(MyResource, self).apply_filters(request, applicable_filters) 

    if self.q_filters: 
     for qf in self.q_filters: 
     filtered = filtered.filter(qf) 
     self.q_filters = [] 

    return filtered 

इस विधि दूसरों कि मैंने देखा है की तुलना में चिंताओं में से एक क्लीनर जुदाई की तरह लगता है:

+0

यह ठीक काम करता है। धन्यवाद – nknganda

+3

शब्दकोश में कोई विधि 'विस्तार' नहीं है। होना चाहिए: orm_filters.update ({'custom': qset}) –

+1

यह समाधान डीबी को दो बार कॉल करने का कारण बनता है (अर्द्ध_फिल्टर के लिए और फिर कस्टम फ़िल्टर के लिए)। मेरे लिए थोड़ा अलग कोड काम करता है: यदि लागू 'फ़िल्टर' में 'कस्टम' है: कस्टम = apply_filters.pop ('custom') वापसी Outreaches.objects.filter (कस्टम) अन्य: वापसी सुपर (आउटरीच रिसोर्स, स्वयं) .apply_filters (अनुरोध, लागू_फिल्टर) –

0

मैं बहुत की तरह इस समस्या का समाधान।

+0

संसाधन उदाहरण पर अनुरोध-विशिष्ट जानकारी डालना वास्तव में एक बुरा विचार है। तो 'self.q_filters.append (a_new_q_object) '।ऐसा इसलिए है क्योंकि कई धागे वाले एक तैनात वातावरण में, आप एक अनुरोध के राज्य के साथ दूसरे के प्रभाव को प्रभावित कर सकते हैं। तो उदाहरण के लिए, एक अनुरोध में बनाए गए सभी फ़िल्टर वास्तव में समय के आधार पर पूरी तरह से अलग-अलग पर लागू किए जा सकते हैं। यहां दस्तावेज़ देखें: http://django-tastypie.readthedocs.io/en/latest/resources.html#why-class- आधारित यह समस्या है जो हर जगह हलचल के आसपास 'बंडल' ऑब्जेक्ट को गुजरती है। –

0

एस्टेवनोविक के जवाब में विचार लेना और इसे थोड़ा साफ करना, निम्नलिखित काम करना चाहिए और अधिक संक्षिप्त होना चाहिए।

मुख्य अंतर यह है कि Nonecustom (जो कॉलम नाम के साथ संघर्ष कर सकता है) की बजाय कुंजी के रूप में लागू_फिल्टर को और अधिक मजबूत बनाया गया है।

def build_filters(self, filters=None): 
    if filters is None: 
     filters = {} 
    orm_filters = super(BusinessResource, self).build_filters(filters) 

    if 'query' in filters: 
     query = filters['query'] 
     qset = (
       Q(name__icontains=query) | 
       Q(description__icontains=query) | 
       Q(email__icontains=query) 
       ) 
     orm_filters.update({None: qset}) # None is used as the key to specify that these are non-keyword filters 

    return orm_filters 

def apply_filters(self, request, applicable_filters): 
    return self.get_object_list(request).filter(*applicable_filters.pop(None, []), **applicable_filters) 
    # Taking the non-keyword filters out of applicable_filters (if any) and applying them as positional arguments to filter() 
संबंधित मुद्दे