'Can I django filter a CharField by range?

How can I filter the prices between 5 and 15 for all the products?

I have this model:

class Product(models.Model):
    price = models.CharField(max_length=150, default= 12)

I tried

Products.objects.all().filter(price__range=(5, 15))

but I get no objects.

Any idea on how to do this?



Solution 1:[1]

Use Cast function and convert the result of price field to integer and then do a range filter

https://docs.djangoproject.com/en/4.0/ref/models/database-functions/#cast

from django.db.models import IntegerField
from django.db.models.functions import Cast

Products.objects.annotate(price_as_int=Cast('price',IntegerField()).filter(price_as_int__range=(5,15))

Solution 2:[2]

For those finding this question on Google looking to actually implement a RangeFilter on a CharField, this is also possible but not by default. First create this class before your filter:

from django import forms
from django_filters import rest_framework as filters, fields

class CharRangeFilter(filters.RangeFilter):
    class CharRangeField(fields.RangeField):
        def __init__(self, *args, **kwargs):
            super().__init__(fields=(
                forms.CharField(),
                forms.CharField()
            ), *args, **kwargs)
        field_class = CharRangeField

And then use it in your filter, like this for example:

class MyFilter(filters.FilterSet):
    my_char_field = CharRangeFilter()

    class Meta:
        model = MyModel
        fields = ['my_char_field']

The reason creating your own RangeField class is because RangeFilter dynamically creates a RangeField, which by default uses two DecimalField objects, and the default can't be changed from the RangeFilter object because RangeFilter is only aware of RangeField via field_class.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Brian Nieves