Django REST frameworkで学んだことをまとめてみた

##はじめに
rayaと申します。
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

##今回の内容
DjangoのREST frameworkで学んだことをまとめてみました。

##DjangoのREST frameworkとは
・Django REST framework
Djangoと組み合わせて、簡単にAPIを作るための設計ルール

・API
外部から呼び出せる機能の塊。
Google mapのAPIを自分のサイトに組み込めば自分のサイトに地図を読み込める

##準備
詳細は公式サイトをご覧ください。
djangoがインストールしてある仮想環境にRest frameworkをインストールします。

```
pip install djangorestframework
```
以下のように、setting.pyファイルにRest frameworkを使用することを伝えます。今回は``tutorial``プロジェクトの中に``snippetes``アプリケーションを作成します。

```python
INSTALLED_APPS = [
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
]
```
##Serialization
snippets/serializer.pyにSerializerを作成します。
Serializerとは、DjangoのFormに似た働きをし、Modelに対してデータを適切な形にして入力、出力するものです。
Serializerにはシリアライズとデシリアライズという働きがあり、シリアライズとは、オブジェクトからデータを読み出すことで、デシリアライズとは、データを元にオブジェクトを作成したり、データを適切な形に変換することです。

models.pyにSnippetモデルを作成した上で、SnippetSerializerを以下のように作成します。

```python
class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
```
``serializers.Serializer``はSerializerの１つで、オブジェクトならばなんでもシリアライズできます。
Fieldの引数に指定されているのはCommon argsで、SerializerのFieldに対して指定でき、以下のようなものがあります。
・read_only
読み込み（出力）専用のフィールドかどうかを指定します。Trueなら読み込みのみ可能です。
・required = False
値を入力しなければならないか否かを指定します。デフォルトだとTrueです。

``{'base_template': 'textarea.html'}``はDjango Formの``widget=widgets.Textarea``に相当します。
widgetはDjangoでHTMLの要素を表現する方法で、Textareaなら\<textarea>\</textarea>を表現しています。

上記の``SnippetSerializer``クラス内に以下のメソッドを定義します。
これらのメソッドはそれぞれ、``serializer.save()``が呼び出された時にインスタンスを作成、更新します（デシリアライズします）。
それぞれの使い分けはメソッド定義の形を見ればわかります。
第一引数が指定されていれば``update``メソッドが、指定されていなければ``create``メソッドが実行されます。
``update``メソッドの定義には``instance``引数が指定されており、これが第１引数になります。

```python
def create(self, validated_data):
        return Snippet.objects.create(**validated_data)

def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
       ...
        instance.save()
        return instance
```
``validated_data``には、バリデーションを通過したデータが格納されます。
バリデーションの通過は、shell上で確認でき、適切なデータだったらTrueになり、``validated_data``に格納されます。

```
snippet = Snippet(code='print("hello, world")\n')

snippet.save()

serializer = SnippetSerializer(snippet)

serializer.is_valid()
# True #適切なデータだったらTrueになり、validated_dataに格納される
```
次は、先ほどとは異なる``serializers.ModelSerializer``を見てみます。
このSerializerでも同様なことがより簡単にできます。
これはModelに紐づいたFieldを自動でSerializerのFieldに定義してくれます。
DjangoのModelFormに似ています。
``serializers.Serializer``はどんなオブジェクトもシリアライズできましたが、``serializers.ModelSerializer``はDjangoモデルのみシリアライズできます。

```python
class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ['id', 'title', 'code', 'linenos']
```
これだけで、SnippetモデルのFieldに基づいたSerializerを作成できます。
##Requests and Responses

REST frameworkにはいくつか中核を担う機能があります。
・Request objects
DjangoのHttpRequestを拡張し、より柔軟になった機能です。
``request.data``属性により、POST、PUT、PATCHで受け取ったデータを処理できます。

・Response objects
return Response(data)でリクエストに応じて適切な形でデータを出力します。

・Status codes
数値のHTTPステータスコードではなく、``HTTP_400_BAD_REQUEST ``のような、そのステータスコードの意味を捉えやすい識別子を提供しています。

・Wrapping API views
API Viewの作成に使える2種類のラッパーがあります。
1. ``@api_view`` : デコレーター。関数ベースのViewの前に記述する。
2. ``APIView`` : クラス。クラスベースのViewに継承する。 
これらはViewに対して``Request``インスタンスを受け取り、``Response``オブジェクトに最適なコンテキストを追加します。

という訳で、これらを使ってViewを作ってみます。

```python
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

@api_view(['GET', 'POST'])
def snippet_list(request):
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```
``status``は``Response``のStatus codesを示します。
CREATED, REQUESTといった識別子が記述されていて、意味が明快です。
``request.data``や``Response``の記述でわかるように、何というかざっくり記述できるようになりました。
``Response``が柔軟にデータを出力するようにできたことで、URLに色々な指定ができます。
まず、Viewに``format``引数を指定します。
この``format``引数に指定した値を接尾子とするURLが提供されるようになります。
``.json``や``.html``をURLに指定できます。
ここではNoneなので特に指定していません。

```python
def snippet_list(request, format=None):
```
次にsnippets/urls.pyファイルに``format_suffix_patterns``を追加します。
これにより先ほどの``format``引数の値で各Viewにより表示されるページのURLを指定できます。

```python
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    path('snippets/', views.snippet_list),
    path('snippets/<int:pk>', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)
```
##Class-based Views
ここまでは関数ベースのViewを使ってきましたが、クラスベースのViewに置き換えてみます。
views.pyを以下のようにします。
``@api_view``デコレーターではなく、``APIView``クラスを使っています。
クラスベースのViewでは、HTTPメソッドをそのままクラスのインスタンスメソッドとして設定します。
このインスタンスメソッドはハンドラメソッドと呼ばれます。

```python
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class SnippetList(APIView):
   
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```
クラスベースのViewを使う場合は、urls.pyのViewの記述を``views.クラス名.as_view()``とします。

```python
urlpatterns = [
    path('snippets/', views.SnippetList.as_view()),
    path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
]
```
さらに簡潔にするためにMixinが使えます。
Mixinとは機能をまとめたクラスのことです。
単体では動作しないため他のクラスに継承して機能を提供する働きをします。
DjangoのREST frameworkのMixinには、作成・取得・更新・削除といった基本的な機能が実装されているので、Mixinを使うことでこれらの機能を簡単に呼び出すことができます。
まず、``GenericAPIView``で``ListModelMixin``と``CreateModelMixin``を追加します。
このGeneric〜に関しては後述します。
これらのMixinクラスにより``.list()``と``.create()``が使えるようになります。

```python
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
```

``*args`` : tupleで複数の値をとる引数
``**kwargs`` : dictionaryでkeyとvalue2つの値をとる引数

実はさらに簡潔に記述できます。
REST　frameworkにはデフォルトでGenericviewが導入されています。
GenericViewは先ほどのGenericAPIViewを基底クラスとし、Mixinを継承しています。
GenericViewクラスに対応した特定のクラスを継承させることで、それに紐づいたアクションメソッドを提供します。
アクションメソッドとはMixinで提供されるハンドラメソッド（上述）のようなものです。
先ほどのViewは以下のように記述できます。

```python
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics

class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
```
##Authentication & Permissions
現状、このAPIは誰もがデータを編集、削除できます。
よって、以下の機能を実装します。
・スニペットとその作成者が関連付けられる。
・認証されたユーザーのみスニペットを作成できる。
・スニペットの作成者のみがそれを更新・削除できる。
・認証されていないリクエストは読み取りのみになる

まず、Userモデルに対する設定をしたいのでUserモデルのSerializerを作ります。
``ModelSerializer``のところで行ったようにUserモデルと関連づけてSerializerを作成します。

```python
from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ['id', 'username', 'snippets']
```
また、GenericViewを使い、Viewを設定します。

```python
from django.contrib.auth.models import User
from snippets.serializers import UserSerializer

class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
```
snippets/urls.pyにもURLを追加します。

```python
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
```
ここからSnippetモデルとUserモデルを関連付けます。
models.pyのSnippetモデルに以下のFieldを追加します。

```python
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
```
さらに``SnippetList``Viewクラスに以下のメソッドを追加します。

```python
def perform_create(self, serializer):
    serializer.save(owner=self.request.user)
```
これで``.perform_create()``メソッドによりリクエストのあったユーザーの情報を``owner``に代入し保存できます。

先ほどはmodels.pyにownerFieldを追加しましたが、次はserializers.pyのSnippetSerializerにownerフィールドを追加します。
この時、class Meta : にもownerを追加します。

```python
owner = serializers.ReadOnlyField(source='owner.username')
```
ここで、``source``引数は、Fieldの引数に指定され、そのFieldに入るシリアライズされたデータの値に属性を指定できます。
この場合は、``owner``Fieldにownerのusernameが入ります。
ReadOnlyFieldはserializerに設定できるフィールドで読み取り専用であることを示します。

次は、認証されたユーザーのみがスニペットを作成し、それらを更新・削除できるようにします。
そのためにViewにPermissionを追加します。
views.pyにPermissionクラスをインポートし、Permissionを追加したいViewにそのPermissionクラスを指定します。

```python
from rest_framework import permissions

#SnippetList Viewに追記
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
```
``IsAuthenticatedOrReadOnly ``は認証されたリクエストを受け取った場合、読み取りと書き込み権限を与え、認証されなければ読み取り権限しか与えないというPermissionです。

ユーザーを認証するるためにはログイン、ログアウト機能を実装し、ユーザー名とパスワードを送ってもらいます。
まず、tutorial/urls.pyに以下の内容を記述します。

```python
from django.conf.urls import include

#ファイルの最後に記述
urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]
```
``'api-auth/'``は任意の値で大丈夫です。
これだけでログイン、ログアウト機能が実装できます。

ここまでは、認証されれば（ログインできれば）、他のユーザーのスニペットを含め、全てのスニペットを編集できるように設定しています。
しかし、スニペットの編集は自分が作成したもののみにしたいですよね。
そこで、次は各オブジェクトに対するパーミッションを設定し、自分の投稿したオブジェクトのみ編集ができるようにします。
そのためにはCustom Permissionを実装する必要があるので、snippet/permissions.pyファイルを作成して以下のように記述します。

```python
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.owner == request.user
```

``Basepermission``と``has_object_permission``によってCustom Permissionが実装され、そのオブジェクトの作成者のみ編集権限を得られるようになります。
``has_object_permission(self, request, view, obj)``メソッドでは、permissionが設定されたViewかつ特定のオブジェクトに対して権限のあるユーザーからのアクセスと保証されるならTrueを返します。
同じような機能の``has_permission(self, request, view)``メソッドでは、permissionが設定されたView全てで呼び出され、権限があるユーザーからのリクエストならばTrueを返しますが、オブジェクトを指定しません。
``SAFE_METHODS``は、``GET, OPTIONS, HEAD``を含むタプルです。
要は読み取りのパーミッションを示しています。
よって、``if request.method in permissions.SAFE_METHODS``以降は、読み取りのリクエストの場合常にTrueになり、読み取りだけなら常に許可します。
それ以外のリクエスト（書き込み）ならば、``return obj.owner == request.user``としてオブジェクトの所有者とリクエストを送ったユーザーが同じならば書き込みを許可します。
このCustom Permissionをviews.pyに設定します。

```python

from snippets.permissions import IsOwnerOrReadOnly

#SnippetDetailクラスに追記（この記事では表記していないので公式サイトでご確認ください）
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly]
```
##Relationships & HyperlinkedAPIs
今のところ、usersとsnippetへのエンドポイントはありますが、API自身のエントリポイントがありません。
そこで、snippet/views.pyに以下の内容を追記してエントリポイントを作ります。

※エントリポイントとエンドポイントとは共に特定のリソースに与えられた一意なURI（web上の住所（URL）とweb上での名前（URN）の総称）で、同じ場所を示します。
その違いは、そのURIにアクセスする視点です。
サービスを提供する側からの視点に立つと、そのURIはプログラムを始める地点という意味でエントリポイントになり、サービスを利用する側からの視点に立つと、そのURIはアクセスさえすればあとはAPIが勝手にプログラムを開始し終了させてくれるという意味でエンドポイントになります。
例えば、Google mapのAPIを自分のサイトで使いたくて、あるURIにアクセスする場合、Google mapから見ればそのURIはエントリポイント、自分から見るとエンドポイントになります。

```python
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse


@api_view(['GET'])
def api_root(request, format=None):
    return Response({
        'users': reverse('user-list', request=request, format=format),
        'snippets': reverse('snippet-list', request=request, format=format)
    })
```
ここで、reverse関数は、URLを完全な形にします。
例えば、``/foobar``ではなく``http://example.com/foobar``で返します。

次に入力した内容のhtml表現をハイライトするコードを導入します。
Restframeworkが提供しているHTML Rendererには2種類あります。
１つは、``TemplateHTMLRenderer``で、templateに基づいたHTMLをレンダリングします。
もう１つは``StaticHTMLRenderer``で、あらかじめレンダリングされたHTMLを処理します。
今回は後者を扱います。
``StaticHTMLRenderer``を使用する際は、APIがこれまでと異なる挙動をするので、GenericViewのメソッドを使わずに、別でViewのメソッドを定義する必要があります。
今回はsnippets/views.pyにget()メソッドを定義していきます。

```python
from rest_framework import renderers
from rest_framework.response import Response

class SnippetHighlight(generics.GenericAPIView):
    queryset = Snippet.objects.all()
    renderer_classes = [renderers.StaticHTMLRenderer]

    def get(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)
```
snippets/urls.pyにここまでに定義したViewのURLを追記します。

```python
path('', views.api_root),
path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view()),
```
ここからは、``HyperLinkedModelSerializer ``を使って、entity間をHyperlinkで繋げます。
entityとは、テキストにリンクをつけるための情報です。
``HyperLinkedModelSerializer ``は``ModelSerializer``とはidフィールドがデフォルトで存在しない点、``HyperlinkedIdentityField``を用いたurlフイールドが存在する点、``HyperLinkedRelatedField``でentity間を繋げる点が異なります。
snippets/serializers.pyに以下の内容を追記します。

```python
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')

    class Meta:
        model = Snippet
        fields = ['url', 'id', 'highlight', 'owner',
                  'title', 'code', 'linenos']

class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
    ##SnippetDetailはこの記事で表記していないので公式サイトでご確認ください

    class Meta:
        model = User
        fields = ['url', 'id', 'username', 'snippets']
```
ここで新たに定義されている``highlight`` Fieldには``format``引数で``html``を指定する必要がある点は注意してください。
``view_name``にはurls.pyで設定したURLの名前が入ります。

UserとSnippetモデルは大量のオブジェクトを返しています。
そこで、１つのページあたりに表示できるオブジェクトの数を制限します。
このことをPaginationと言います。
tutorial/settings.pyに以下の内容を追記します。

```python
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}
```

##Viewsets & Routers
REST frameworkにはURLの構築を自動で行ってくれるViewsetという仕組みがあります。
Viewsetクラスは、Viewクラスとほとんど同じですが、GET,PUTなどのHTTPメソッドではなく、read,updateなどのCRUDでデータをサーバーとやりとりします。
※厳密には、Viewsetクラスがインスタンス化される瞬間にHTTPメソッドは使われます。（後述）

ここまで作ってきたViewをViewsetに置き換えます。
UserListクラスとUserDetailクラスを１つのUserViewsetクラスにまとめます。
``ReadOnlyModelViewSet``クラスによって「読み取り機能」が設定され、list, detailというアクションが自動で定義されます。

```python
from rest_framework import viewsets

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
```
次は、``SnippetList``,``SnippetDetail``, ``SnippetHighlight``クラスを``SnippetViewset``にまとめます。

```python
from rest_framework.decorators import action
from rest_framework.response import Response

class SnippetViewSet(viewsets.ModelViewSet):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
```
ここでは``ModelViewset``によって「読み書き機能」が設定され、list, create, retrieve, update, destroyが自動で定義されます。
また、CRUD以外のアクションを追加したい時は、``@action``の後に記述でき、``highlight``, ``perform_create``アクションが定義されています。
一応、これらのアクションにはGETメソッドがデフォルトで割り当てられます。
他のHTTPメソッドにも対応させたい場合は、``method``引数で指定できます。

※``detail``引数について間違ってたらコメントお願いします！
これはかなり自分なりの解釈ですが、
``detail=``はTrueならpkの設定が必要になり、データ１つあたりに対してアクションを起こしたい場合に使用され、Falseの場合はpkが不要でデータ一覧に対してアクションを起こしたい場合に使用されます。 

次にViewsetとURLを繋げます。
具体的には、Viewsetの各アクションをHTTPメソッドへどう割り当てるかをsnippets/urls.pyで定めます。

```python

from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers

snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})
```
その後、URLconf（tutorial/urls.py）で実際にURLを設定します。

```python
urlpatterns = format_suffix_patterns([
    path('', api_root),
    path('snippets/', snippet_list, name='snippet-list'),
    path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
    path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
    path('users/', user_list, name='user-list'),
    path('users/<int:pk>/', user_detail, name='user-detail')
])
```
しかし、最初に言ったように、実際はViewsetクラスを使っているため、自分でURLを設定する必要はありません。
それはRouterクラスが自動で行ってくれます。
Routerクラスが機能するようにsnippets/urls.pyを書き換えると以下のようになります。

```python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

#Routerクラスを作り、Viewsetクラスを登録する
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

#URLが自動で割り当てられる
urlpatterns = [
    path('', include(router.urls)),
]
```
``DefaultRouter``クラスは自動でAPIルートビューを作るので、Relationships & HyperlinkedAPIsのところで作成したViewsモジュールから``api_root``メソッドを削除できます。

##メモ
Tutorialの中で気になって調べたことを一部まとめています。
メモ程度に書いているのでご了承ください。

・参照と逆参照

```python
class Food(models.Model):
    name = models.CharField(max_length=100)

class Person(models.Model):
    name = models.CharField(max_length=100)
    favorite_food = models.ForeignKey(Food, on_delete="CASCADE", null=True)
```

foreignkeyフィールドを設定してあるモデルからその関連するモデルのカラムを取得するときは参照。

```python
person1 = Person.objects.get(name="ジョブス")
person1.favorite_food
インスタンス.フィールド名
```

foreignkeyフィールドの設定してない方のモデルからそれち関連したforeignkeyフィールドの設定したあるモデルのフォールドを参照する場合は逆参照

```python
food1 = Food.objects.get(name="寿司")
food1.person_set.all()
インスタンス.クラス名_set
```
・repr(serializer)
str()と似ている。

・from django.http import HttpResponse, JsonResponse
辞書型のオブジェクトをJsonreaponseに渡し、returnするとjsonで送信できる

・from django.views.decorators.csrf import csrf_exempt
csrf_tokenを渡していないPOSTメソッドはエラーになるが、それを無効化する。関数の上に``@csrf_exempt``を記述

・from rest_framework.parsers import JSONParser
parserは、構文を解析するプログラム。

・many=True
引数にmany=Trueを指定すると複数のデータをまとめて扱えるようになる。

・safe=False
文字列に対してエスケープが必要でないと示す

・Pastebin
保存したデータを公開できるウェブアプリケーションのサービス。
##参考
・公式サイト(https://www.django-rest-framework.org)
・https://qiita.com/ryoo17/items/326f8adda8423abf1ce4
・https://note.crohaco.net/2018/django-rest-framework-serializer/
・http://sandmark.hateblo.jp/entry/2017/09/30/160945
・https://qiita.com/NagaokaKenichi/items/6298eb8960570c7ad2e9
・https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8