2017-03-29 14 views
5

मेरे मॉडलएक क्वेरीसेट कैसे बनाएं जो Django में एक शर्त पर आधारित एकाधिक फ़ील्ड फ़िल्टर करता है?

class TestModel(models.Model) 
    field1 = models.IntegerField() 
    field2 = models.IntegerField() 
    field3 = models.IntegerField() 
    field4 = models.IntegerField() 
    field5 = models.IntegerField() 

मैं क्षेत्रों के प्रत्येक संयोजन के लिखने और उन्हें छानने के बिना सभी पांच मॉडल के क्षेत्रों पर एक भी शर्त लागू होने वाला एक सरल क्वेरीसमूह की जरूरत है।

उदाहरण के लिए मैं दो या अधिक क्षेत्रों

TestModel.objects.filter(two_or_more_fields=None) 

मैं किसी भी दो या अधिक क्षेत्रों के साथ क्वेरीसमूह को खोजने के लिए 5 क्षेत्रों के हर संभव संयोजन लिखना नहीं चाहते करने के लिए कोई नहीं के लिए जाँच की एक शर्त लागू करना चाहते हैं कोई नहीं के रूप में।

from django.db.models import Q 
TestModel.objects.filter(
    #condition for exactly 2 None 
    Q(field1=None & field2=None) | 
    Q(field2=None & field3=None) | 
    Q(field3=None & field4=None) | 
    Q(field4=None & field5=None) | 
    Q(field5=None & field1=None) | 
    #condition for more than 2 None 
    Q(field1=None & field2=None & field3 = None) | 
    ''''' 
    . 
    . 
    #so on to cover all possible cases of any two or more fields as None 
    ) 

मुझे लगता एक बेहतर और आसान तरीका यह पूरा करने के होना चाहिए: दूसरे शब्दों में, वहाँ एक बेहतर तरीका है पूरा करने के लिए इस से है।

उत्तर

3

घंटों खर्च करने के बाद मुझे Django फ़िल्टर संरचनाओं में निर्मित का उपयोग करके ऐसा करने का एक आसान तरीका नहीं मिला।

field_list = ['field1', 'field2', 'field3', 'field4', 'field5'] 

def get_all_possible_filter_dict_list_for_a_condition(field_list): 

    all_possible_filter_dict_for_a_condition = [] 
    for field_1, field_2 in combinations(field_list, 2): 
     all_possible_filter_dict_for_a_condition.append(
     { 
     field_1:None, 
     field_2:None 
     } 
     ) 
    return all_possible_filter_dict_for_a_condition 


def get_qs_list_to_perform_or_operation(all_possible_filter_dict_list_for_a_condition): 

    qs_list_to_perform_or_operation = [] 
    for i, filter_dict in enumerate(all_possible_filter_dict_list_for_a_condition): 
     qs_to_append = qs.filter(**filter_dict) 
     qs_list_to_perform_or_operation.append(qs_to_append) 
    return qs_list_to_perform_or_operation 


def get_qs_to_filter_fields_with_more_than_1_none(qs_list_to_perform_or_operation): 

    final_qs = qs_list_to_perform_or_operation [0] 
    for i in range(len(qs_list_to_perform_or_operation) - 1): 
     final_qs = final_qs | qs_list[i + 1] 
    return final_qs 

all_possible_filter_dict_list_for_a_condition 
    = get_all_possible_filter_dict_list_for_a_condition(field_list) 
qs_list_to_perform_or_operation = get_qs_list_to_perform_or_operation(all_possible_filter_dict_list_for_a_condition) 
final_qs_to_filter_multiple_fields_with_same_condtion = get_qs_to_filter_fields_with_more_than_1_none(qs_list_to_perform_or_operation) 
1

मुझे Django में गैर शून्य क्षेत्रों की संख्या द्वारा फ़िल्टर करने के लिए किसी भी विधि से अवगत नहीं है।

एक कम बेकार और लुकअप-कुशल वर्कअराउंड मैं सुझाव दूंगा कि मॉडल में खुद को फ़ील्ड के रूप में शून्य फ़ील्ड (null_count) की संख्या स्टोर करना है।

आप TestModel की विधि को आसानी से ओवरराइड करके ऐसा कर सकते हैं।

def save(self, *args, **kwargs): 
    self.null_count = 0 
    self.null_count += 1 if self.field1 is None else 0 
    # update null_count for 4 remaining fields 
    super(TestModel, self).save(*args, **kwargs) 

और देखें, null_count पर फ़िल्टर करें।

TestModel.objects.filter(null_count_gt=2) 
+0

यह एक अच्छा सुझाव है, लेकिन मैं मेरे मामले में मॉडल नहीं बदल सकते। – javed

0

यह समाधान यहां इस्तेमाल किया कार्यों की वजह से PostgreSQL विशिष्ट है: हालांकि मैं इस समाधान जो मैं क्या खोज रहा था के करीब है पाया। हालांकि, यदि आप किसी अन्य डेटाबेस का उपयोग कर रहे हैं तो विचार का उपयोग किया जा सकता है।


आप RawSQL का एक मिश्रण है और कुछ ARRAY जादू इस्तेमाल कर सकते हैं।

विचार क्षेत्रों जो अशक्त नहीं हैं की संख्या के साथ क्वेरीसमूह में प्रत्येक आइटम पर टिप्पणी करने के लिए है:

from django.db.models import Func 
from django.db.models.expressions import RawSQL 

field_list = ['field1', 'field2', 'field3', 'field4', 'field5'] 

# field1 IS NULL, field2 IS NULL, field3 IS NULL, ..... 
statements = ", ".join("{} IS NULL".format(field) for field in field_list) 

# create an array for each field by checking if those are NULL 
# then, remove the False values e.g. not null ones. 
# ARRAY_REMOVE(ARRAY[field1 IS NULL, field2 IS NULL, .....], false) 
raw_sql = "ARRAY_REMOVE(ARRAY[{statements}], false)".format(statements=statements) 

# now annotate each item with the number of null fields 
qs = TestModel.objects.annotate(num_null=Func(RawSQL(sql,()), function='CARDINALITY') 

# on this queryset you can filter by the number of null items you want to check 
qs = qs.filter(num_null__gte=2) 
+0

क्या यह आपके लिए काम करता है? – AKS

संबंधित मुद्दे