'Django write Q filter based on the Form elements

I would like to write django filter for the following scenario. CASE : I have 4 checkboxes box1, box2, box3, box4 and a submit button on my HTML page.

I have written model post with 6 fieldd where 4 fields corresponds to box1,2,3,4. Based on the user input (4 checkboxes) it should filter the post. However does this mean i have to write 16 scenarios 4x4. or is it possible to formulate it in a better way. offcourse using if elif

post.objects.filter(Q(id=1),Q(sid=1),Q(pid=1),Q(kid=1)) # case 1
post.objects.filter(Q(id=1),Q(sid=1))
post.objects.filter(Q(id=1),Q(kid=1))
post.objects.filter(Q(id=1),Q(pid=1))
post.objects.filter(Q(kid=1),Q(sid=1))
.
.
.
post.objects.filter(Q(kid=1))

Is there a better way to do it?



Solution 1:[1]

No. You can build up a queryset filter by filter based on the form input.

qs = Post.objects.all()
if form.cleaned_data['id']:  # I don't know what you have called the form fields
    qs = qs.filter(Q(id=1))
if form.cleaned_data['kid']:
    qs = qs.filter(Q(kid=1))
if form.cleaned_data['pid']:
    qs = qs.filter(Q(pid=1))
if form.cleaned_data['sid']:
    qs = qs.filter(Q(sid=1))

Note, you don't need Q objects for AND-logic. You can just use qs.filter( id=1 ).filter( sid=1).filter ...

Q objects are necessary if you want OR logic, in which case you would build up a compound Q object from a set of elementary ones. Something like

qlist = []
if form.cleaned_data['id']:
   qlist.append( Q(id=1))
...
if qlist:
   qq = qlist[0]
   for q in qlist[1:]
      qq = qq | q      # OR-logic
   qs = qs.filter( qq)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1