Home > Back-end >  How to Filter within a Filter in Django
How to Filter within a Filter in Django

Time:08-11

I'm trying to filter category with age range. I want to see people with certain genders and then their age range.

My models:

from django.db import models

# Create your models here.

class catagory(models.Model):
    name = models.CharField(max_length=150)

    def __str__(self):
        return self.name


class Age(models.Model):
    range = models.CharField(max_length=150)

    def __str__(self):
        return self.range


class person(models.Model):
    name = models.CharField(max_length=100)
    gender = models.ForeignKey(catagory, on_delete=models.CASCADE)
    age_range = models.ForeignKey(Age, on_delete=models.CASCADE)

    @staticmethod
    def get_person_by_cataegoryID(categoryID):
        if categoryID:
            return person.objects.filter(gender=categoryID)
        else:
            return person.objects.all()

    @staticmethod
    def get_person_by_age_range(AGE_RANGE):
        if AGE_RANGE:
            return person.objects.filter(age_range=AGE_RANGE)
        else:
            return person.objects.all()

    def __str__(self):
        return self.name

My views

    from django.shortcuts import render
from .models import catagory,person,Age

# Create your views here.

def index(request):
    c = catagory.objects.all()
    categoryID = request.GET.get('category')
    AGE_RANGE = request.GET.get('age_range')



    p= person.objects.all()
    a = Age.objects.all()
    if categoryID:
        persons = person.get_person_by_cataegoryID(categoryID)
    elif AGE_RANGE:
        persons = person.get_person_by_age_range(AGE_RANGE)
    else:
        persons = person.objects.all()

    context = {
        "person": p,
        "catagory": c,
        "age": a
    }

    context["person"] = persons

    return render(request, "index.html", context)

My Template

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>hello</h2>
<div style="display:flex;height:100vh;width:100vw;align-items:center;justify-content:space-around;">

    <div style="display:flex;flex-direction:column;">
        {% for a in age %}
        <a href="/?age_range={{a.id}}">{{a.range}}</a>
        {% endfor %}
    </div>
  <div style="display:flex;flex-direction:column;">
      <a href="/">All</a>
    {% for c in catagory %}
      <a href="/?category={{c.id}}">{{c.name}}</a>
    {% endfor %}
  </div>
  <br>
  <div style="display:flex;flex-direction:column;">
    {% for p in person %}
      <p>{{p.name}}</p>
     {% endfor %}

  </div>
</div>

</body>
</html>

Please tell me what I'm doing wrong here. The filters work by themselves correctly but my goal is to see a specific gender and then that gender's age range. Currently it shows the gender and age range of the whole group.

CodePudding user response:

if you need gender and age at the same time:

if categoryID and AGE_RANGE:
    persons = person.objects.filter(gender=categoryID, age_range=AGE_RANGE)     
elif categoryID:
    persons = person.get_person_by_cataegoryID(categoryID)
elif AGE_RANGE:
    persons = person.get_person_by_age_range(AGE_RANGE)
else:
    persons = person.objects.all()

CodePudding user response:

You can use ** dictionary unpacking to determine your model filters. The dictionary itself is created based on whether category/age_range exist in request.GET:

category = request.GET.get('category')
age_range = request.GET.get('age_range')

filters = {}
if category:
    filters['category'] = categoryID
if age_range:
    filters['age_range'] = AGE_RANGE
    
persons = person.objects.filter(**filters)

If filters is an empty dict then it has the same effect as calling all()

Edit - you could also use a list an dict comprehension to remove the if-statement:

fields = ['category','age_range']
filters = {k: v for k, v in request_GET.items() if k in fields and v is not None}
  • Related