trial_and_error
trial_and_error

Reputation: 147

objects.filter() and Foreign Key NULL

I've written a complex search form in Django.

Here is my example model:

class student(models.Model):
   name = models.CharField(max_length=255)
   school = models.ForeignKey('school', null=True, blank=True)
class school(models.Model):
    name = models.CharField(max_length=255)

So student uses a FK for school. It should be optional, so null=True and blank=True is used. If I want search for students with a specific school name I use a form with HTML code like this:

<input type="text" name="school_name"/>

And I do query the database like this (example):

def search(request):
 results = student.objects.filter(
    name__icontains=request.POST.get('student_name',''),
    school__name__icontains=request.POST.get('school_name','')
     )

Problem is: If I leave the search form empty, it should display all students, because no filter is applied. Thats works, if every student has set a school. If a student has no school set, it's value in MySQL is 'NULL'. I assume they could not be found, because an empty string is not NULL. But how can I avoid that? Do I have to write an if-statement before every filter expression? We talk about 50-100 fields to filter for!

I'd be thankful for every hint to solve this.

Upvotes: 1

Views: 2030

Answers (1)

Simeon Visser
Simeon Visser

Reputation: 122336

You could write it like this:

query = {
    'name__icontains': request.POST.get('student_name',''),
}
school_name = request.POST.get('school_name', None)
if school_name is not None:
    query['school__name__icontains'] = school_name
results = student.objects.filter(**query)

And similarly for the other fields. This would mean one if statement for each field. You can even do this dynamically as the keys in query are just strings. That means you can compute them as well and add them to query when needed.

Upvotes: 2

Related Questions