書くこと
django-filterで用意されているDateFromToRangeFilter()
を使うと、デフォルトでは指定したfieldのsuffixに_after
と_before
がついた物を拾ってその範囲で絞り込んでくれます。
ただ、今回自分は_from
と_to
を拾って範囲絞り込みをして欲しかったです。
少し時間がかかってしまったので、記録として記事にします。
GitHubにもあげておきました。
準備
created_at
カラムを持つBlogModel
を作って、そのlistを取得するエンドポイントを作成します。
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
from rest_framework.serializers import ModelSerializer
from blogs.models import Blog
class BlogSerializer(ModelSerializer):
class Meta:
model = Blog
fields = '__all__'
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']
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)
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)で使われています。
以上から
- CustomWidgetを作成
- CustomDateRangeFieldを作成
- CustomDateFromToRangeFilterを作成
のように実装することにしました。
実装
1. CustomWidgetを作成
suffixが_from
, _to
になるようにします
from django_filters.widgets import DateRangeWidget
class CustomDateRangeWidget(DateRangeWidget):
suffixes = ['from', 'to']
2. CustomDateRangeFieldを作成
CustomWidgetを使ってFilterに使用するためのFieldを作ります。
from django_filters.fields import DateRangeField
from blogs.widgets import CustomDateRangeWidget
class CustomDateRangeField(DateRangeField):
widget = CustomDateRangeWidget
3. CustomDateFromToRangeFilterを作成
2で作ったCustomDateRangeField
を使ってFilterを作成します。
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
ですが、非常に便利ですね。
「これもっと簡単に解決出来るよ」というのをご存知の方がいれば教えていただけると嬉しいです。
ありがとうございました!