Django models with hard coded model fields in filtersets

This question is about filtering. But to explain here is some supporting facts...

There is a concept in my program of objects being virtual or not virtual. Using rest_framework I have two models in my models.py:

class ModelA(models.Model):
    @property
    def is_virtual(self):
        return False

class ModelB(ModelA):
    @property
    def is_virtual(self):
        return True

So ModelB inherits ModelA. And ALL ModelA objects are NOT virtual, and ALL ModelB objects ARE virtual. Instead of adding this to the database where the column is always True for ModelAs and False for ModelBs I would like to hardcode it in the model class and supporting classes.

In my serializers.py I have:

class ModelSerializer(serializers.ModelSerializer):
    is_virtual = serializers.SerializerMethodField()

    def get_is_virtual(self, obj):
        return obj.is_virtual

class ModelASerializer(ModelSerializer):
    class Meta:
        model = ModelA
        fields = '__all__'

class ModelBSerializer(ModelSerializer):
    class Meta:
        model = ModelB
        fields = '__all__'

All this above basically works UNTIL I want to filter search on is_virtual. In my filters.py:

class ModelFilterSet(filters.FilterSet):
    is_virtual = filters.BooleanFilter(method='filter_is_virtual')

    def filter_is_virtual(self, queryset, name, value):
        if value:
            return queryset.filter(is_virtual=True)
        else:
            return queryset.filter(is_virtual=False)

Then when I GET http://localhost:8080/api/modela/?is_virtual=false I get:

Internal Server Error: /api/modela/
Traceback (most recent call last):
  File "D:\projects\my_app\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "D:\projects\my_app\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\django\views\decorators\csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\mixins.py", line 38, in list
    queryset = self.filter_queryset(self.get_queryset())
  File "D:\projects\my_app\venv\lib\site-packages\rest_framework\generics.py", line 150, in filter_queryset
    queryset = backend().filter_queryset(self.request, queryset, self)
  File "D:\projects\my_app\venv\lib\site-packages\django_filters\rest_framework\backends.py", line 74, in filter_queryset
    return filterset.qs
  File "D:\projects\my_app\venv\lib\site-packages\django_filters\filterset.py", line 230, in qs
    qs = self.filter_queryset(qs)
  File "D:\projects\my_app\venv\lib\site-packages\django_filters\filterset.py", line 213, in filter_queryset
    queryset = self.filters[name].filter(queryset, value)
  File "D:\projects\my_app\venv\lib\site-packages\django_filters\filters.py", line 820, in __call__
    return self.method(qs, self.f.field_name, value)
  File "D:\projects\my_app\core\filters.py", line 65, in filter_is_virtual
    return queryset.filter(is_virtual=False)
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\query.py", line 1476, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\query.py", line 1494, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\query.py", line 1501, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\sql\query.py", line 1602, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\sql\query.py", line 1634, in _add_q
    child_clause, needed_inner = self.build_filter(
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\sql\query.py", line 1484, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg, summarize)
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\sql\query.py", line 1296, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
  File "D:\projects\my_app\venv\lib\site-packages\django\db\models\sql\query.py", line 1761, in names_to_path
    raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword 'is_virtual' into field. Choices are: <LISTS ALL THE OTHER FIELDS OF MODELA>
[22/Feb/2024 13:00:20] "GET /api/modela/?is_virtual=false HTTP/1.1" 500 159755

I see that it is complaining about the line in filters.py:

else:
    return queryset.filter(is_virtual=False)

But my model declares it as a property and the serializer recognises is_virtual as well. What am I doing wrong? Thanks in advance.

You can only filter on fields of model, while using queryset is_virtual() is a method and not a field

else: return queryset.filter(is_virtual=False)

What you can do is add the is_virtual field in like this:

`class ModelA(models.Model):
       is_virtual = models.BooleanField(default=False)`
Back to Top