Building query from non-empty search parameters only

My search form contains three fields, one of which (content) is much more expensive than the others. So my search view adds each parameter to the query only if the user actually used the respective field:

def search(request):
	if request.method == 'POST':
		form = SearchForm(request.POST)
		if form.is_valid():
			formfields_parameters = [('page_content', 'content__icontains'), ('page_author', 'author__last_name__icontains'), ('page_title', 'title__icontains')]
			search_dict = {}
			for (formfield, parameter) in formfields_parameters:
				if form.cleaned_data[formfield]:
					search_dict[parameter] = form.cleaned_data[formfield]
			results = Page.objects.filter(**search_dict).defer('content').order_by('title')

This works well, but looks a little clumsy. Is there a better/more elegant way to achieve the same result?

Can you share your SearchForm code.

And also, Is there any situation by which all three field maybe used to search … ?

Side note: Whatever streamlining is done here will have negligible effect on the overall performance. The time required for the query itself is going to be orders of magnitude larger than any improvement you can achieve in building this query.

You can get “fancier”, but I’m not sure those options are any more elegent.

For example, you could build the search_dict incrementally, within the form, in the individual clean_ methods of the form. You would create clean_page_content, clean_page_author, and clean_page_title methods - each checking for content and adding to the search_dict.

You could use the search terms as the names of the fields, and iterate over them in the form’s clean method. (This is only helpful if these three search fields are the only fields in that form.)

You could rewrite the code you posted here to use a dict-comprehension.

But, it’s up to you to decide what best expresses the intent behind this, because you are the person that’s going to need to come back to this in 6 - 12 months and try to remember what you were thinking when you wrote it.

Sure, it is very simple:

class SearchForm(forms.Form):
	page_title = forms.CharField(max_length=100, min_length=4, label = 'Titel', required=False)
	page_content = forms.CharField(max_length=100, min_length=4, label = 'Inhalt', required=False)
	page_author = forms.CharField(max_length=100, min_length=4, label = 'Autorin', required=False)

The user can fill out any combination of the three fields.

I am aware that my solution already addresses the actual bottleneck effectively. I was just wondering whether there is a more efficient solution, and will experiment with the options you pointed out. Thank you!

Probably not - as I said in my previous reply, any difference in execution time between the solutions is going to be a rounding error compared to the time necessary for the query itself.

What I presented as solutions are an attempt to provide other implementations that would satisfy your original stated criteria:

… Which is not the same thing.

You’re right – I mixed up (at least) two different goals, and probably should not invest too much time in improving maintainable code that works well.