2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

django-filter/DateFromToRangeFilterのsuffixを変更する

Posted at

書くこと

django-filterで用意されているDateFromToRangeFilter()を使うと、デフォルトでは指定したfieldのsuffixに_after_beforeがついた物を拾ってその範囲で絞り込んでくれます。

ただ、今回自分は_from_toを拾って範囲絞り込みをして欲しかったです。

少し時間がかかってしまったので、記録として記事にします。

GitHubにもあげておきました。

準備

created_atカラムを持つBlogModelを作って、そのlistを取得するエンドポイントを作成します。

models.py
from django.db import models


class Blog(models.Model):
    title = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
serializers.py
from rest_framework.serializers import ModelSerializer

from blogs.models import Blog


class BlogSerializer(ModelSerializer):
    class Meta:
        model = Blog
        fields = '__all__'
filters.py
from django_filters import rest_framework as filters

from blogs.models import Blog


class BlogFilter(filters.FilterSet):
    created_at = filters.DateFromToRangeFilter()

    class Meta:
        model = Blog
        fields = ['created_at']
views.py
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet

from blogs.filters import BlogFilter
from blogs.models import Blog
from blogs.serializers import BlogSerializer


class BlogViewSet(ViewSet):
    def list(self, request):
        queryset = Blog.objects.all()
        queryset = BlogFilter(data=request.GET, queryset=queryset, request=request).qs
        serializer = BlogSerializer(queryset, many=True)
        return Response(serializer.data)
urls.py
from rest_framework.routers import DefaultRouter

from blogs.views import BlogViewSet

router = DefaultRouter(trailing_slash=False)

router.register(
    r'^blogs',
    BlogViewSet,
    basename='blogs'
)

urlpatterns = router.urls

最後に2020年02月24日にBlogテーブルにレコードを作成します。

>>> blog1 = Blog.objects.create(title='blog1')
<Blog: Blog object (1)>
>>> blog1.created_at
datetime.datetime(2020, 2, 24, 5, 54, 52, 859528, tzinfo=<UTC>)

これで/blogsにクエリパラメータcreated_at_after, created_at_beforeを渡して範囲指定が出来るようになりました。

>>> curl 'http://localhost:18000/blogs?created_at_after=2020-02-01&created_at_before=2020-02-02'
[]

>>> curl 'http://localhost:18000/blogs?created_at_after=2020-02-01&created_at_before=2020-02-28'
[{"id":1,"title":"blog1","created_at":"2020-02-24T05:54:52.859528Z"}]

方針

今回したいことは、デフォルトで設定されているsuffixの_after, _beforeを変更するということです。

設定されているところを見つけて可能そうであればオーバーライドする等で対応しようと考えました。

DateFromToRangeFilterの中をのぞいてみます。
DateFromToRangeFilter(GitHub)

そうするとDateRangeWidget(GitHub)でこのようにsuffixが設定されていることが分かりました。

class DateRangeWidget(RangeWidget):
    suffixes = ['after', 'before']

これはDateRangeField(GitHub)で使われています。

以上から

  1. CustomWidgetを作成
  2. CustomDateRangeFieldを作成
  3. CustomDateFromToRangeFilterを作成
    のように実装することにしました。

実装

1. CustomWidgetを作成

suffixが_from, _toになるようにします

widgets.py
from django_filters.widgets import DateRangeWidget


class CustomDateRangeWidget(DateRangeWidget):
    suffixes = ['from', 'to']

2. CustomDateRangeFieldを作成

CustomWidgetを使ってFilterに使用するためのFieldを作ります。

fields.py
from django_filters.fields import DateRangeField

from blogs.widgets import CustomDateRangeWidget


class CustomDateRangeField(DateRangeField):
    widget = CustomDateRangeWidget

3. CustomDateFromToRangeFilterを作成

2で作ったCustomDateRangeFieldを使ってFilterを作成します。

filters.py
from django_filters import rest_framework as filters

from blogs.fields import CustomDateRangeField
from blogs.models import Blog


class CustomDateRangeFilter(filters.DateFromToRangeFilter):
    field_class = CustomDateRangeField


class BlogFilter(filters.FilterSet):
    # created_at = filters.DateFromToRangeFilter()
    created_at = CustomDateRangeFilter()

    class Meta:
        model = Blog
        fields = ['created_at']

もちろんデフォルトで用意されている_after, _beforeは使えなくなります。

確認しておきます。

_after,_beforeが使えないことを試す
>>> curl 'http://localhost:18000/blogs?created_at_after=2020-02-01&created_at_before=2020-02-02'
[{"id":1,"title":"blog1","created_at":"2020-02-24T05:54:52.859528Z"}]

>>> curl 'http://localhost:18000/blogs?created_at_after=2020-02-01&created_at_before=2020-02-28'
[{"id":1,"title":"blog1","created_at":"2020-02-24T05:54:52.859528Z"}]

_from, _toが期待通りに動作することを試す
>>> curl 'http://localhost:18000/blogs?created_at_from=2020-02-01&created_at_to=2020-02-02'
[]

>>> curl 'http://localhost:18000/blogs?created_at_from=2020-02-01&created_at_to=2020-02-28'
[{"id":1,"title":"blog1","created_at":"2020-02-24T05:54:52.859528Z"}]

以上でsuffixを変更することが出来ました。

最後に

今まで全く使ってこなかったdjango-filterですが、非常に便利ですね。

「これもっと簡単に解決出来るよ」というのをご存知の方がいれば教えていただけると嬉しいです。

ありがとうございました!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?