Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter on range of datetimes in django rest framework

I have a model with a field named start_time which is of type DateTimeField. I want to query a range which overlaps this field. Django filters contains a DateFromToRangeFilter filter which works perfectly for dates but not for datetime strings (unless I'm querying incorrectly). Here's what I've tried so far:

Created a DatetimeFromToRangeFilter:

class DatetimeRangeField(RangeField):
    def __init__(self, *args, **kwargs):
        fields = (
            forms.DateTimeField(),
            forms.DateTimeField())
        super(DatetimeRangeField, self).__init__(fields, *args, **kwargs)

    def compress(self, data_list):
        if data_list:
            start_datetime, stop_datetime = data_list
            if start_datetime:
                start_datetime = datetime.combine(start_datetime, time.min)
                if stop_datetime:
                    stop_datetime = datetime.combine(stop_datetime, time.max)
                    return slice(start_datetime, stop_datetime)
        return None

class DatetimeFromToRangeFilter(RangeFilter):
    field_class = DatetimeRangeField

Use this as a filter:

class TestRunFilter(filters.FilterSet):
    start_time = filters.DatetimeFromToRangeFilter()

    class Meta:
        model = models.TestRun
        fields = ['start_time',]

When I query the endpoint with /test_runs/?start_time_0=2015-09-05 or /test_runs/?start_time_0=2015-09-05%2000:00:00 it does nothing to filter the queryset.

When I change the filter to django_filters.DateFromToRangeFilter the first query returns the appropriate queryset, the second query returns a null queryset.

like image 534
Collin Reynolds Avatar asked Oct 24 '25 04:10

Collin Reynolds


1 Answers

It looks like you have some improper indentation, in comparison to the DateRangeField provided by django-filter.

In django_filters/fields.py:

        if start_date:
            start_date = datetime.combine(start_date, time.min)
        if stop_date:
            stop_date = datetime.combine(stop_date, time.max)
        return slice(start_date, stop_date)

In your code:

        if start_datetime:
            start_datetime = datetime.combine(start_datetime, time.min)
            if stop_datetime:
                stop_datetime = datetime.combine(stop_datetime, time.max)
                return slice(start_datetime, stop_datetime)

Try making the indentation levels match and that should take care of your problem.

like image 175
Joey Wilhelm Avatar answered Oct 26 '25 23:10

Joey Wilhelm