Django REST FRAMEWORK Tutorial 9 -- snippet_detail の GET/PUT/DELTE を APIView で作成する
Tags: django
Published: 2022-04-21 14:34:08


https://www.django-rest-framework.org/tutorial/2-requests-and-responses/#pulling-it-all-together

Django REST framework の snippet_detail を

```py
@csrf_exempt
  def snippet_detail(request, pk):
```

CSRF の検出除外 から

```py
@api_view(['GET', 'PUT', 'DELETE'])
  def snippet_detail(request, pk):
```

API view に書き直す。
これによって DjangoRestFramework の管理画面がブラウザで使える。


```py
from django.http import HttpResponse
```

HttpResponse を使っていたのを

```py
from rest_framework.response import Response
```

REST framework の Response に変更


```py
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)
```

この、HttpResponse を

```py
        return Response(status=status.HTTP_404_NOT_FOUND)
```

Response にして、`status.HTTP_404_NOT_FOUND` を返すようにする

前回の記事で削除した snippets/2 をブラウザで見ると

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hxf7hnsaqwkkhsq470i.png)

ちゃんと 404 で DRF の管理画面で表示されている。

しかし、api_view を入れずに csrf_exempt のままだと

> "GET /snippets/2/ HTTP/1.1" 500 59081

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6z3buo8xezlmshceils.png)

404 ではなく 500 が返ってきてしまう。

404 は想定されるエラーで、500 はちゃんと想定できていない、システムの作りが甘い時に出るエラーなんだなぁということが理解できた

## GET

```py
    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)
```

GET の Jsonレスポンスも レスポンスにすることで

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/747mgf3738a3b3ymrzmw.png)

DRF の管理画面で綺麗に見れる。

## PUT, DELETE

```py
    elif request.method == 'PUT':
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
```

PUT と DELETE も snippet_list の時のように
DRF の Response と HTTP ステータスを用いて書き直す。
こちらの方が　204 がなんだっけって考えずに済むので可読性が高い。


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6jv16odrhtidrat4w7b0.png)

PUT と DELETE は、この詳細画面でボタンから行える。

---

## snippet_detail 全体

```py
@api_view(['GET', 'PUT', 'DELETE',])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
```

---

## format=None をつける

https://www.django-rest-framework.org/tutorial/2-requests-and-responses/#adding-optional-format-suffixes-to-our-urls

format=None をつけると .json などの format 接尾辞をつけてリクエストをできるらしい
　
```py
def snippet_list(request):
def snippet_detail(request, pk):
```

snippet_list, snippet_detail, の引数に 

```py
def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
```

format=None をつけて

snippets/urls.py に

```py
from rest_framework.urlpatterns import format_suffix_patterns

urlpatterns = format_suffix_patterns(urlpatterns)
```

urlpatterns を format_suffix_patterns をかける

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aveff6d1binkihknanjo.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/575tkpya6mbcxqzzkcfw.png)

すると、拡張子に応じて DRF の管理画面と json のみを返すものと切り替えられる。


---

## まとめ

```py
from rest_framework.decorators import api_view

@api_view(['GET', 'PUT', 'DELETE'])
```

rest_framework の api_view で
snippet_detail など各関数（エンドポイント？）で使う HTTP メソッドを記述して

```py
from rest_framework import status
from rest_framework.response import Response

return Response(serializer.data, status=status.HTTP_201_CREATED)
```

rest_framework の status, Response で
このように `status.HTTP_201_CREATED`, `status.HTTP_204_NO_CONTENT`,  `status.HTTP_400_BAD_REQUEST`, `status.HTTP_404_NOT_FOUND`, これらを使うようにする。