Как фильтровать внутри фильтра в Django

Я пытаюсь отфильтровать категории по возрастному диапазону. Я хочу видеть людей с определенным полом, а затем их возрастной диапазон.

Мои модели:

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

Мои взгляды

    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)

Мой шаблон

    <!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>

Пожалуйста, подскажите, что я делаю не так. Фильтры работают сами по себе правильно, но моя цель - увидеть определенный пол, а затем возрастной диапазон этого пола. В настоящее время он показывает пол и возрастной диапазон всей группы.

если вам нужен пол и возраст одновременно:

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()

Для определения фильтров модели можно использовать распаковку словаря **. Сам словарь создается на основе того, существуют ли категория/возрастной_диапазон в 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)

Если filters - пустой dict, то это имеет тот же эффект, что и вызов all()

Edit - вы также можете использовать список или диктующее понимание для удаления if-условия:

fields = ['category','age_range']
filters = {k: v for k, v in request_GET.items() if k in fields and v is not None}
Вернуться на верх