Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest filter custom fields

I am converting a UNIX date to a string date and passing it as a custom read-only field. What would be the best way to use django-filter to be able to filter this custom field? The error I get is Cannot resolve keyword 'convert_time' into the field. Choices are:

Models class

class AccountT(models.Model):
    created_date_t = models.BigIntegerField(blank=True, null=True)
    def convert_time(self):
        result = time.strftime("%D", time.localtime(self.created_date_t))
        return result

Serializer Class

class AccountTSerializer(serializers.ModelSerializer):
    created_date = serializers.ReadOnlyField(source='convert_time')
    class Meta:
        model = AccountT
        fields = ('othermodelfield','othermodelfield', 'created_date',)

ListAPIView

class AccountTListView(generics.ListAPIView):
    serializer_class = AccountTSerializer
    queryset = AccountT.objects.all()
    filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter,)
    filter_fields = ('othermodelfield','created_date_t')
like image 773
Allee Clark Avatar asked Aug 12 '26 19:08

Allee Clark


1 Answers

The filterset_fields option is a shortcut that inspects model fields (not serializer fields) in order to generate filters. Since created_date isn't a model field, you'll need to manually declare a filter on a filterset_class. Declared filters can take advantage of the method argument, which will allow you to transform the incoming date into your timestamp. Something like...

# filters.py
from django_filters import rest_framework as filters

class AccountTFilter(filters.FilterSet):
    # could alternatively use IsoDateTimeFilter instead of assuming local time.
    created_date = filters.DateTimeFilter(name='created_date_t', method='filter_timestamp')

    class Meta:
        model = models.AccountT
        # 'filterset_fields' simply proxies the 'Meta.fields' option
        # Also, it isn't necessary to include declared fields here
        fields = ['othermodelfield']

    def filter_timestamp(self, queryset, name, value):
        # transform datetime into timestamp
        value = ...

        return queryset.filter(**{name: value})

# views.py
class AccountTListView(generics.ListAPIView):
    filterset_class = filters.AccountTFilter
    ...

Note: The old filter_* options have since been renamed to filtserset_*.

like image 112
Sherpa Avatar answered Aug 14 '26 10:08

Sherpa