django rest framework : viewset

# description

以下の内容を記述する

-   目的
    -   rest frameworkのviewsetを用い, restful api を作成する

-   手順
    -   django setup
    -   rest framework
        -   viewset を用いての構築

# 環境
- mac sierra
- pyenv 
    - python 3.6.5


# viewset 対応 methods
| method | path          | 動作|
|--------|---------------|---|
| get    | */users/* | 一覧取得 |
| post   | */users/* | 作成 |
| get    | */users/*:id/ | 一件取得|
| put    | */users/*:id/ | 更新 |
| patch  | */users/*:id/ | 部分更新 |
| delete | */users/*:id/ | 一件削除|


# project dir, file 構造
```
.
├── manage.py
├── api
│   ├── models.py       // db構造設定
│   ├── serializers.py  // api に用いる data の seriaze/deseriaze 設定
│   ├── urls.py         // api app の url設定
│   ├── views.py        // 処理
│   └── migrations
└── rest_project
    ├── settings.py     // django の全体設定
    └── urls.py         // project全体の url 設定. 各app へ path を通す
```

# django setup

## pip install

```shell:shell
pip install django djangorestframework
```

## generate project

``` bash:shell
django-admin startproject rest_project
```

# rest framework, app : prepare

## generate app

```bash:shell
cd rest_project
python manage.py startapp api
```

## enable app, rest framework

```python:rest_project/settings.py
# 追記
INSTALLED_APPS = [
    ...,
    'api',
    'rest_framework',
]
```

## path settings

```python:rest_project/urls.py
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls', namespace = 'api'))
]

```

# resf framework : coding

## create model

```python:api/models.py
from django.db import models
from django.db.models import CharField


class User(models.Model):
    name = models.CharField(blank=False, null=False, max_length=255)
    profile = models.CharField(max_length=255)

    def __str__(self):
        return u'%d' % (self.pk)

    def __repr__(self):
        return u'%d: %s' % (self.pk, self.user)

    class Meta:
        db_table = 'user'
        app_label = 'api'
```

## prepare serializer

```python:api/serializers.py
from rest_framework import serializers
from api.models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('pk', 'name', 'profile')
```
- serialize/deserialize(json, model data間の変換) する column を定義


## viewset

```python:api/views.py
from rest_framework import viewsets
from rest_framework.response import Response

from api.models import User

from .serializers import UserSerializer

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().select_related()
    serializer_class = UserSerializer
```

- 継承する viewset により, read only api などの制約を課せる
    - ModelViewSet は, 前述の6種の rest api path に対応する
    - ReadOnlyModelViewSet は, get method のみに対応する

## route

```python:api/urls.py
from django.conf.urls import url, include
from rest_framework import routers
from .views import UserViewSet

router = routers.DefaultRouter()
router.register(r'^users', UserViewSet)

urlpatterns = [
    url(r'^',  include(router.urls)),
]
```
- viewset で定義した path を生成する

# django : run

```bash:shell
python manage.py makemigrations
python manage.py migrate

python manage.py runserver 0.0.0.0:9000
```

# django : api test

という感じで使用出来るようになる

```bash:shell
$ curl localhost:9000/api/users/

[]
```

```bash:shell
$ curl -X POST -H 'Content-Type:application/json' \
    -d '{"name":"test_user","profile":"test_profile"}' \
    localhost:9000/api/users/

{"pk":1,"name":"test_user","profile":"test_profile"}
```

```bash:shell
$ curl localhost:9000/api/users/

[{"pk":1,"name":"test_user","profile":"test_profile"}]
```

```bash:shell
$ curl localhost:9000/api/users/1/

{"pk":1,"name":"test_user","profile":"test_profile"}
```

# 参考サイト
http://www.django-rest-framework.org/api-guide/viewsets/#readonlymodelviewset