概要
この記事は初心者の自分がRESTfulなAPIとswiftでiPhone向けのクーポン配信サービスを開発した手順を順番に記事にしています。技術要素を1つずつ調べながら実装したため、とても遠回りな実装となっております。
前回の Django Rest Framework で 特定のデータだけレスポンスするようにフィルタを設定する で、 Generic Filtering を使って指定したフィールドのパラメータに一致するデータをフィルタリングできました。しかしこの方法では指定したパラメータに対して 「以上」、「以下」という条件でフィルタリングする事が出来ません。
そこで今回は日付について「〜より前」「〜より後」といった条件で有効期限を判定するフィルタ機能を実装します。
Django-Filter
をインストールされていない場合は前回の記事を参考にインストールしてください。
参考
環境
Mac OS 10.15
VSCode 1.39.2
pipenv 2018.11.26
Python 3.7.4
Django 2.2.6
手順
- views.py にFilterSetのクラスを作る
- 既存のViewSetでFilterSetを呼ぶ処理を追加
- 試してみる
views.py にFilterSetのクラスを作る
django_filter の FilterSetクラスを継承してオリジナルのフィルターセットを作ります。
まずFilterSetクラスをインポートするための処理を追加します。
from django_filters import rest_framework as filters
次に、ViewSetのクラスの前にオリジナルのフィルターセットを実装します。
class CustomFilter(filters.FilterSet):
# フィルタの定義
deadline = filters.DateFilter(field_name='deadline', lookup_expr='gte')
class Meta:
model = Coupon
fields = ['deadline'] #定義したフィルタを列挙
下記の部分がフィルタの設定になります。今回はDateFilterを使いますが、他にも文字列のフィルターや数値のフィルターなど、沢山あります。詳しくは公式ドキュメントで!
deadline = filters.DateFilter(field_name='deadline', lookup_expr='gte')
補足
上記の field_name = ‘ ‘
は フィルタリングしたいモデルフィールドの名前を指定します。ここへ名前を指定しない場合はフィルタ定義の名前(上記のコードだと deadline
の部分)がフィルタリング対象のモデルフィールドの名前として扱われます。
(サンプルコードには field_name
を指定していますが、フィルタ定義の名前と同じであれば実は不要です)
リクエストする際のパラメータ名はフィルタ定義の名前になります。つまり、リクエストする際のパラメータ名をモデルフィールドの名前と異なる名前にしたい場合は field_name の設定が必要です。
下記のmodel = ~
には、フィルタリングしたデータのモデル名を設定します。
Fields = [~]
には、フィルタ定義の名前を列挙します。
class Meta:
model = Coupon
fields = ['deadline']
既存のViewSetでFilterSetを呼ぶ処理を追加
上記で実装したフィルタクラスをfilter_classとして呼ぶだけです。
filter_class = CustomFilter
試してみる
見積5分 → 5分
リクエストパラメータとして、クーポンの有効期限を示す deadline
を指定しない場合と、する場合で GETできるデータの違いを比較します。
パラメータ deadline を指定しない場合
リクエスト
curl -X GET http://127.0.0.1:8000/api/coupons/
レスポンス
[{"id":1,"code":"0001","benefit":"お会計から1,000円割引","explanation":"5,000円以上ご利用のお客様限定。他クーポンとの併用不可。","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":2,"code":"0002","benefit":"お会計を10%オフ!","explanation":"他クーポンとの併用不可","store":"有楽町店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":3,"code":"0003","benefit":"【ハロウィン限定】仮装して来店すると30%オフ","explanation":"全身の50%以上を仮装されているお客様限定(判断はスタッフの感覚とさせて頂きます)。他クーポンとの併用不可","store":"神田店","start":"2019-10-31","deadline":"2019-10-31","status":true},{"id":4,"code":"0004","benefit":"【9月限定】お月見団子サービス","explanation":"ご希望のお客様に月見団子をプレゼント! 他クーポンとの併用可能です!","store":"全店","start":"2019-09-01","deadline":"2019-09-30","status":true},{"id":5,"code":"0005","benefit":"【雨の日限定】お会計から15%オフ","explanation":"クーポンが配信された時だけ利用可能です。他クーポンとの併用不可","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":false},{"id":6,"code":"0006","benefit":"【日曜日限定】乾杯テキーラサービス","explanation":"テキーラを人数分サービスします。他クーポンとの併用可。","store":"神田店","start":"2019-11-03","deadline":"2019-12-01","status":true},{"id":7,"code":"0007","benefit":"お会計から19%引き","explanation":"12月29日~12月31日限定。他のクーポンとの併用不可","store":"神田店","start":"2019-12-29","deadline":"2019-12-31","status":true}]
deadlineを指定する場合
リクエスト(有効期限が12月5日以降のクーポンだけリクエスト)
curl -X GET http://127.0.0.1:8000/api/coupons/?deadline=2019-12-05
レスポンス
[{"id":1,"code":"0001","benefit":"お会計から1,000円割引","explanation":"5,000円以上ご利用のお客様限定。他クーポンとの併用不可。","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":2,"code":"0002","benefit":"お会計を10%オフ!","explanation":"他クーポンとの併用不可","store":"有楽町店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":5,"code":"0005","benefit":"【雨の日限定】お会計から15%オフ","explanation":"クーポンが配信された時だけ利用可能です。他クーポンとの併用不可","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":false},{"id":7,"code":"0007","benefit":"お会計から19%引き","explanation":"12月29日~12月31日限定。他のクーポンとの併用不可","store":"神田店","start":"2019-12-29","deadline":"2019-12-31","status":true}]
有効期限が12月5日以降のクーポンのみGET出来ました。