Meta.fields contains a field that isn't defined on this FilterSet: ****

Ilya Bibik picture Ilya Bibik · Oct 16, 2016 · Viewed 9.6k times · Source

I am using Django Filters package .

I define my filter in following way in the view

class UnitFilter(django_filters.FilterSet):
    class Meta:
        model = Unit
        fields = [
            'floor', 'number', 'building','lease','leaseterm', 
            'lease__is_active','lease__is_terminated','lease__is_renewed',]

My Unit Model on which I filter is following

class Unit(CommonInfo):
    version = IntegerVersionField( )
    number = models.CharField(max_length=30,null=True, blank=True)
    max_occupants = models.PositiveSmallIntegerField()
    floor = models.PositiveSmallIntegerField()
    rooms = models.PositiveSmallIntegerField()
    is_disabled_access = models.BooleanField(default=False)
    balcony_quantity = models.PositiveSmallIntegerField()
    building = models.ForeignKey(Building)
    recomended_price = models.DecimalField(max_digits=7, decimal_places=2)
    _lease = None
    _leaseterm = None
    #check = models.ManyToManyField(UnitCheck, through='UnitChecklist')

    def _get_total(self):

        from conditions.models import LeaseTerm
        from lease.models import Lease

        lease_dict = Lease.objects.filter(unit_id=self.id, is_active = True , is_terminated = False).aggregate(Max('id'))
        if lease_dict['id__max']:
            lease =  lease_dict['id__max'] 
        else:  
            lease =  0

        leaseterm_dict = LeaseTerm.objects.filter(lease_id=lease, is_active = True , is_terminated = False).aggregate(Max('id'))
        if leaseterm_dict['id__max']:
            leaseterm =  leaseterm_dict['id__max'] 
        else:  
            leaseterm =  0

        self._lease = lease
        self._leaseterm = leaseterm

    @property
    def lease(self):
        if self._lease is None:
            self._get_total()
        return self._lease

    @property
    def leaseterm(self):
        if self._leaseterm is None:
            self._get_total()
        return self._leaseterm

There is 2 calculated properties in this model lease and leaseterm

lease property has no problem when leaseterm gives me this error

Meta.fields contains a field that isn't defined on this FilterSet: leaseterm

why? it it a bug in django-filter?Any work around?

Answer

Sam Bobel picture Sam Bobel · Oct 30, 2017

See this for a good explanation.

When you do queryset.filter(field_name=field_value), Django translates that into a SQL query. Unfortunately, calculated properties only live on the Python object, so you can't filter by them.

The workaround is to, whenever you filter by one of these, include an annotation to your queryset that adds the proper field in SQL. The link has a good example of how to do this. It's harder than doing it in Python, but the only way to go really.