Django Rest Framework で 特定のデータだけレスポンスするようにフィルタを設定する

# 概要

　この記事は初心者の自分がRESTful なAPIとswiftでiPhone向けのクーポン配信サービスを開発した手順を順番に記事にしています。技術要素を1つずつ調べながら実装したため、とても遠回りな実装となっています。

前回の [Django Rest Framework で RESTful な APIを作成する](https://qiita.com/Ajyarimochi/items/1345a49d70805db289a7) でRest API の基本的な仕組みが出来上がりました。次は、条件の合致するデータをリクエストパラメータでフィルタできるように改造します。

django-rest-framework で構築したAPIにフィルタリングを実装するには、Generic Filtering というのが便利らしいので、それを使う方法で実装します。

### 参考

* [適当に作る python Djnago REST frameworkで作る初めてのAPI](https://qiita.com/MuuKojima/items/3ea452fd69756db9e815)

### 環境
Mac OS 10.15
VSCode 1.39.2
pipenv 2018.11.26
Python 3.7.4
Django 2.2.6


# 手順

* django-filter をインストール
* フィルタが使えるように setting.py に追記 
* views.py にfilter_fields を追記する
* 試してみる

### django-filter をインストールする

 pipenvで作ったpythonのプロジェクト（仮想環境）にdjango-filter をインストールします。pipenvのシェルに入り、下記のインストールのコマンドを実行。

```
$ pipenv install django-filter
```

Pipfileを確認すると、[packages]に django-filter が追加されています。

```
(amiApp) bash-3.2$ cat Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
django = "*"
djangorestframework = "*"
django-filter = "*"

[requires]
python_version = "3.7"
```


### フィルタが使えるように setting.py に追記 

 `ami_coupon_api/setting.py` の `INSTALLED_APPS`  に django_filters を追記

```ami_coupon_api/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'coupon',
    'rest_framework',
    'django_filters', # 追加した
```

次に、`ami_coupon_api/setting.py`に`REST_FRAMEWORK = {}` の項目を作って、フィルタが使えるように下記の設定を追加します。

```ami_coupon_api/settings.py

REST_FRAMEWORK = {
    #フィルタを追加
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
```


### views.py にfilter_fields を追記する

　`CouponViewSet`クラスで`filter_fields`を呼び出し、フィルタしたいcouponモデルのモデルフィールド名（couponテーブルの項目）を`filter_fields`の引数に設定するだけです。複数の設定も可能です。`filter_fields`に設定したフィールド名を使ってレスポンスするデータのフィルタリングが行えます。

```coupon/views.py

class CouponViewSet(viewsets.ModelViewSet):
    queryset = Coupon.objects.all()
    serializer_class = CouponSerializer
    filter_fields = ('status','code')　#追加した
```

### 試してみる

curl コマンドでリクエストしてみます。URLの末尾に `?[条件]` を付けます。条件の部分は、`filter_fields`に設定したモデルフィールド名を使います。

例えば、モデルフィールドの`status`が "false" のクーポンだけGETしたい場合はURLの末尾に`?status=false`を付けて下記のようにリクエストします。

```
curl -X GET http://127.0.0.1:8000/api/coupons/?status=false
```

分かりにくいですが、下記の通り`status`が`false`になっているid=5のクーポンのみGET出来ました。

---
[{"id":5,"code":"0005","benefit":"【雨の日限定】お会計から15%オフ","explanation":"クーポンが配信された時だけ利用可能です。他クーポンとの併用不可","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":false}]

---

`filter_fields`には`code`もフィルタ対象のフィールド名として設定しているので、`code`でフィルタする場合も試してみます。

例えば、`code`が0007のクーポンだけGETするリクエストはURLの末尾に`?code=0007`を付けて下記の通りになります。

```
curl -X GET http://127.0.0.1:8000/api/coupons/?code=0007
```

`code`が0007のクーポンのみGET出来ました。

---
[{"id":7,"code":"0007","benefit":"お会計から19%引き","explanation":"１２月２９日～１２月３１日限定。他のクーポンとの併用不可","store":"神田店","start":"2019-12-29","deadline":"2019-12-31","status":true}]

---


ここまでで、特定のデータ項目に完全一位するデータを取得する処理が実装できました。しかし日付のように「以前」や「以降」という条件のフィルタもクーポン配信では必要になります。

次は、[Django-Filterを使ってフィルタのカスタマイズをします。](https://qiita.com/Ajyarimochi/items/a88331825667ce27cf48)