[Django][RESTframework]追加、更新、取得の簡単な動的APIを作成する 備忘録

##前書き
すごく遠回りしながらなんとか作成できたAPIについて備忘録を残す。

今回作ったAPIは以下のようになる

```
# ユーザーの登録
http://127.0.0.1:8000/v1/user/

# pk=1 のユーザー情報を更新   
http://127.0.0.1:8000/v1/user/1/

# pk=2 のユーザー情報を取得
http://127.0.0.1:8000/v1/user/2/affinity
```


##準備
プロジェクト名：project
アプリ名    :api

###構成

```
└─project
   ├─api
   │ ├─migrations
   │ │ └─..
   │ ├─__init__.py
   │ ├─apps.py
   │ ├─models.py
   │ ├─serializer.py
   │ ├─urls.py
   │ └─views.py
   ├─project
   │ ├─__init__.py
   │ ├─asgi.py
   │ ├─settings.py
   │ ├─urls.py
   │ └─wsgi.py
   ├─db.sqlite3
   └─manage.py
```

###プロジェクト作成

```
$ django-admin startproject project 
$ cd project
$ python manage.py startapp api

$ brew install mysql
$ pip install pymysql
$ pip install djangorestframework
$ pip install django-filter

$ mysql.server start 
# mysql.server stop でサーバー停止

#MySQLに入る
$ mysql -u root
```

MySQLの操作

```
mysql> show databases;
mysql> create database sample;
mysql> show databases;
mysql> exit
```

##manage.py

```manage.py
import pymysql #追加
pymysql.install_as_MySQLdb() #追加
```


```
$ python manage.py migrate

$ mysql -u root

mysql> use sample;
mysql> show tables;
mysql> exit
```


##settings.py

```settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api',            #追加
    'rest_framework', #追加
    'django_filters', #追加
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'sample',  # 作成したデータベース名
        'USER': 'root',  # ログインユーザー名
        'HOST': '',
        'PORT': '',
    }
}

# ペジネーション
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 5
}


LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'
```

##models.py
最初にモデルを作成する
データベースに保存する内容を記述

```models.py
from django.db import models

"""
CharField (文字列が入る)文字数制限必要
TextField(文章が入る)
ImageField(写真ファイルが入る)
FileField(不特定のファイルが入る)
IntegerField(数値が入る)オーバーフロー注意
BooleanField(True/False)が入る *いわゆるフラッグ
DateField(日付が入る)
DateTimeField(日時が入る)
ForeignKey(外部キー) *一対多のリレーションになる。（言葉だけでも覚えておきましょう！）
ManyToManyField(複数の外部キーが入る) *多対多のリレーションになる
OneToOneField(外部キー) *一対一のリレーションになる
"""
class BaseAPI(models.Model):

    first_name = models.CharField(max_length=32)
    last_name = models.CharField(max_length=32)

    class Meta:
        verbose_name_plural = "ベースAPI"
```



##serializer.py
Modelに対してデータを適切な形にして入力、出力するもの
-[参考サイト6]

```serializer.py
# coding: utf-8
from .models import BaseAPI
from rest_framework import serializers

class BaseAPISerializer(serializers.ModelSerializer):

    class Meta:
        model = BaseAPI
        fields = (
            'first_name',
            'last_name'
        )
```


##views.py
Viewの設定については[ここを参照](https://www.django-rest-framework.org/api-guide/generic-views/#listapiview)

| クラス | 操作 | 
|:-----------------|:------------------|
| CreateAPIView | 登録（POST） |
| ListAPIView | 一覧取得（GET） |
| RetrieveAPIView | 取得（GET） |
| UpdateAPIView | 更新（PUT、PATCH） |
| DestroyAPIView | 削除（DELETE） | 
-[参考サイト3]


```views.py
# coding: utf-8
from .models import BaseAPI
from .serializer import BaseAPISerializer
from rest_framework import generics


class BaseAPIViewSet_POST(generics.CreateAPIView):
    queryset = BaseAPI.objects.all()
    serializer_class = BaseAPISerializer


class BaseAPIViewSet_PUT(generics.UpdateAPIView):
    queryset = BaseAPI.objects.all()
    serializer_class = BaseAPISerializer


class BaseAPIViewSet_GET(generics.RetrieveAPIView):
    queryset = BaseAPI.objects.all()
    serializer_class = BaseAPISerializer
```



##project/urls.py
v1は慣習でAPIのバージョンを表すそう　Ver 1.0.1みたいな

```urls.py
"""プロジェクト名 URL Configuration

'urlpatterns'リストはURLをビューにルーティングします。
詳細は以下を参照してください。
https://docs.djangoproject.com/en/3.1/topics/http/urls/
例を紹介します。
関数ビュー
    1. インポートの追加: from アプリ名 import views
    2. urlpatternsにURLを追加する: path('', views.home, name='home')
クラスベースのビュー
    1. インポートの追加： from 他のアプリ名.views import Home
    2. urlpatternsにURLを追加する: path('', Home.as_view(), name='home')
別の URLconf を含む
    1. include() 関数をインポートします: from django.urls import include, path
    2. urlpatternsにURLを追加する: path('blog/', include('blog.urls')
"""

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('v1/', include('api.urls')),
]
```




##api/urls.py
動的なルーティングを行いたい場合
< str:pk > と記述する　

```app/urls.py
# coding: utf-8
from django.urls import path
from .views import BaseAPIViewSet_POST, BaseAPIViewSet_PUT, BaseAPIViewSet_GET

app_name = 'api'
urlpatterns = [
    path('user/', BaseAPIViewSet_POST.as_view(), name='POST'),
    path('user/<str:pk>/', BaseAPIViewSet_PUT.as_view(), name='PUT'),
    path('user/<str:pk>/affinity', BaseAPIViewSet_GET.as_view(), name='GET'),
]
```

```
$ python manage.py runserver 
```

```
# ユーザーの登録
http://127.0.0.1:8000/v1/user/
```
![スクリーンショット 2021-03-05 15.09.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/2843f97e-2c86-13eb-7f4e-245ac667318d.png)



```
# pk=1 のユーザー情報を更新 
# (存在しないpkを指定するとサイトにアクセスできないと表示される)
http://127.0.0.1:8000/v1/user/1/

# pk=2 のユーザー情報を取得
# (存在しないpkを指定するとサイトにアクセスできないと表示される)
http://127.0.0.1:8000/v1/user/2/affinity
```

これで完成

もしURLのpkを取得したい場合は
[この記事](https://qiita.com/akidon0000/items/87fbdee64ecd1f0e3eff)
の書き方を参照

##参考サイト
1, [Django REST Framework の使い方メモ](https://qiita.com/__init__/items/f5a5a64a05541fcda713)
2, [Django REST Frameworkを使って爆速でAPIを実装する](https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8)
3, [DRFのGeneric viewの使い方](https://qiita.com/murapon/items/8a6a1715712ddd1a4ac1)
4, [Django REST framework カスタマイズ方法 - チュートリアルの補足](https://qiita.com/okoppe8/items/c58bb3faaf26c9e2f27f)
5, [Django 開発者への道① ~ Modelsを理解する ~](https://qiita.com/kotayanagi/items/3cfadae951c407ac044a)
6, [Django REST frameworkで学んだことをまとめてみた](https://qiita.com/breakthrough/items/f845592961d8863a72c5#:~:text=Serializer%E3%81%A8%E3%81%AF%E3%80%81Django%E3%81%AE,%E5%85%A5%E5%8A%9B%E3%80%81%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A7%E3%81%99%E3%80%82&text=serializers.Serializer%20%E3%81%AFSerializer%E3%81%AE,%E3%81%B0%E3%81%AA%E3%82%93%E3%81%A7%E3%82%82%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82)