Django-filter 2 use @property to filter?

Viewed 481

I've got this filter:

class SchoolFilter(django_filters.FilterSet):
    class Meta:
        model = School
        fields = {
            'name': ['icontains'],
            'special_id': ['icontains'],
        }

Where special_id is a @property of the School Model:

@property
    def special_id(self):
        type = self.type
        unique_id = self.unique_id
        code = self.code
        if unique_id < 10:
            unique_id = f'0{unique_id}'
        if int(self.code) < 10:
            code = f'0{self.code}'
        special_id = f'{code}{type}{id}'
        return special_id

I've tried to google some answers, but couldn't find anything. Right now If I use my filter like I do I only receive this error:

'Meta.fields' contains fields that are not defined on this FilterSet: special_id

How could I define the property as a field for this FilterSet? Is it even possible for me to use django-filter with a @property?

Thanks for any answer!

Update:

Figured it out. Not the prettiest solution, but ayyy

class SchoolFilter(django_filters.FilterSet):
    special_id = django_filters.CharFilter(field_name="special_id", method="special_id_filter", label="Special School ID")

    def special_id_filter(self, queryset, name, value):
        schools_pk = []
        for obj in queryset:
            if obj.special_id == value:
                schools_pk.append(obj.pk)
        queryset = queryset.filter(pk__in=schools_pk)
        return queryset

    class Meta:
        model = School
        fields = {
            'name': ['icontains'],
            'special_id': ['icontains'],
        }
2 Answers

You can't. FilterSet will only filter on actual fields, since FilterSet alters a QuerySet.

QuerySets do a database call based on the filters applied, which means you can only filter on fields actually stored in the database.

You could annotate your QuerySet to add the special_id, but an annotation like this is pretty complex to chain together.

A better way to do this would be to create a custom filter on your FilterSet, but I'm not exactly sure how to do this. If you can explain what special_id is, and exactly why you want to search it through icontains, then I could maybe point you in the right direction.

This is an implementation of a MethodFilter, which I think is similar what you want.

FilterSet operates by filtering queryset (adding where conditions to the underlying sql). Which means, FilterSet can operate only on Columns that are present in the database. Here the special_id is a computed property (It is not a column, it is calculated on the fly using other fields/columns), So it wont work.

The work around is to make special_id a normal field/column, compute the value at runtime and write to database at the time of save.

Related