Django Queryset with custom property

Viewed 575

django==3.0.5 django-filter==2.3.0 djongo==1.3.3 my database is mongodb I have a simple model like below

class Parishioner(models.Model):

    def _age(self):
        return date.today().year - self.dob.year

    """Parishioner model"""
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    dob = models.DateField()
    age = property(_age)
    GENDER_CHOICES = [("Male", "Male"), ("Female", "Female"), ("Other", "Other")]
    gender = models.CharField(max_length=10, choices=GENDER_CHOICES)
    address = models.CharField(max_length=1000)
    fathers_name = models.CharField(max_length=500)
    mothers_name = models.CharField(max_length=500)
    baptism_certificate = models.ImageField(null=True, upload_to=baptism_certificates_image_file_path)
    marriage_certificate = models.ImageField(null=True, upload_to=marriage_certificates_image_file_path)

As you can see age is a calculated property.

I have my viewset like below

class ParishionerViewSet(viewsets.ModelViewSet):
    queryset = Parishioner.objects.all()
    serializer_class = serializers.ParishionerSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        first_name = self.request.query_params.get('first_name')
        last_name = self.request.query_params.get('last_name')
        gender = self.request.query_params.get('gender')
        address = self.request.query_params.get('address')
        fathers_name = self.request.query_params.get('fathers_name')
        mothers_name = self.request.query_params.get('mothers_name')
        age = int(self.request.query_params.get('age'))
        queryset = self.queryset
        
        if first_name:
            queryset = queryset.filter(first_name__contains=first_name)
        if last_name:
            queryset = queryset.filter(last_name__contains=last_name)
        if gender:
            queryset = queryset.filter(gender__contains=gender)
        if address:
            queryset = queryset.filter(address__contains=address)
        if fathers_name:
            queryset = queryset.filter(fathers_name__contains=fathers_name)
        if mothers_name:
            queryset = queryset.filter(mothers_name__contains=mothers_name)
        if age:
            queryset = queryset.filter(age__gte=age)
        return queryset.filter()

All I want is to return obects who has age >= provides value. So if I send a request to this url http://localhost:8000/api/parishioners/?age=32 I'm getting this error --> Cannot resolve keyword 'age' into field

So how can I use this url http://localhost:8000/api/parishioners/?age=32 and get objects who has age greater than or equal to 32 ?

1 Answers

You cannot use a function / property of the model in a query. You need to bring the logic of the function into the query instead.

from django.db.models.functions import ExtractYear, Now

queryset = queryset.annotate(age=ExtractYear(Now()) - ExtractYear('dob')).filter(age__gte=age)
Related