1

I don't know if there's a quick way to do this, but what I want to do is a search according to six parameters, where 5 of them come from Select Inputs, and the other one from an Input text, the search needs to be more specific when more options are selected.

Is there a way to do this with lookups? Or I need to make an if for every combination of parameters? If I have to write all the if's, what is the more efficient way? Because if I'll have to do 2^6 if statements to cover all the combinations, that will be a little bit slow. Consider that the parameters doesn't have an specific order, so any combination is possible.

I was thinking in Q objects but I don't know if they work for that, I have only used them for OR satements, I know that they can be used for and statements too, but I don't know if they are different than using comma. Probably something like this:

result = Product.objects.filter(Q(field1=param1)&Q(field2=param2)&Q(field3=param3)&Q(field4=param4)&Q(field5=param5)&Q(field6=param6))
elG
  • 539
  • 1
  • 6
  • 20

2 Answers2

2

It seems like you probably have access to a form's cleaned_data and you're looking to do something like an "advanced search." In that case, given that all of the form fields are relevant to the search, you could do something like

result = Product.objects.filter(**form.cleaned_data)

since you want to only include fields that are specified you can then add a filtering statement to ensure you're only looking at the relevant fields. Unfortunately, that depends a lot on how your form looks. If your form's non-empty values are all truthy, you could do something like

result = Product.objects.filter(**{k: v for k, v in form.cleaned_data.items() if v})

If on the other hand, you only want to apply filters where the fields have changed from what they populated the form with, you might be well served by

result = Product.objects.filter(**{k: v for k, v in form.cleaned_data.items() if form.changed_data})

Unfortunately, if you have a checkbox named turtle_safe, you'll need to record whether someone's indicated that they want results that are safe for turtles or results that are not safe for turtles. Both of the follow up approaches I've suggested would not apply a filter for "not safe for turtles" and would instead filter for "no preference for turtle safety" (assuming the default is False in the option with changed_data).

If that isn't sufficient, you may be able to avoid posting fields that the user hasn't deliberately selected by disabling / enabling the fields with javascript until the user adds them for their search.

If you end up with that, you may want to set the default values to None and use the second check (so long as None isn't a valid option!).

Alex Riina
  • 801
  • 7
  • 11
  • That's really good, but I forgot to say that I'm using AJAX for the requests, so I have "plain" variables, not forms. But this looks interesting, I'm going to try it in other searches where I submit the entire form. – elG Sep 10 '16 at 17:01
  • FYI form data can work just fine with AJAX data. Just send it to the same view and the form will pick it up. You'll probably want a json response though. http://stackoverflow.com/a/8244082/3208419 – Alex Riina Sep 10 '16 at 17:04
  • Oh, that's why formData() exists haha, that's why I think DJango is amazing, it automates a lot of programming. With formData() I send the data, and in DJango just receive it like: myform=theform(request.POST), just like a normal submit right? – elG Sep 10 '16 at 17:14
  • Exactly! The javascript is a little tricky because those extra parameters (processData and contentType) are required. – Alex Riina Sep 10 '16 at 19:37
1

You do not have to use Q and &. Every filter operation does and with previous. So You will have the same number of if operations as parameters.

q = Product.objects.all()
if param1 != None:
    q = q.filter(field1=param1)
if param2 != None:
    q = q.filter(field2=param2)
#and so on

It is equivalent to your code but with if.