Django REST framework(DRF) 公式チュートリアル① Serialization【和訳】

はじめに

こんにちは、PDG部のエンジニアUnitの野崎です!

今回、DRF(Django REST framework)の公式チュートリアルTutorial 1: Serializationの内容をもとに、和訳および補足解説を行ってみました。

私がDRFのチュートリアルで Web API を学んだとき、全6回を通して和訳された記事が見つからず、原文のまま読んで進めることになりました。
最近では ChatGPT などの生成AIを使えば、わかりやすい訳を出してくれるので便利なのですが、毎回コピペして翻訳させるのも意外と手間だったりします。

そこで今回、同じように「DRF のチュートリアルを無料でやってみたいけど、英語がちょっと苦手……」という方の助けになればと思い、この和訳シリーズを書きました。

※記事内のコードや内容は、Django REST frameworkによるオリジナルチュートリアルを元にしています。著作権は全てDRFの運営元に帰属します。

基本的にはチュートリアルの翻訳を軸に構成しており、✏️補足の箇所では、各コードセクションの補足や内部処理の解説を備忘録的に記載しています。

それでは、本チュートリアルを始めましょう。

イントロダクション

このチュートリアルでは、シンプルなPastebin風のコードハイライトWeb APIの作成を扱います。その過程で、REST frameworkを構成するさまざまなコンポーネントを紹介し、すべての仕組みがどのように組み合わさっているのかを包括的に理解できるようになります。

このチュートリアルはかなり詳しく書かれているので、始める前にクッキーとお気に入りの飲み物を用意するのがおすすめです。
ざっと全体像を知りたいだけなら、代わりにQuickstartドキュメントを読むとよいでしょう。

補足: このチュートリアルのコードはGitHubのencode/rest-framework-tutorialリポジトリで利用できます。気軽にリポジトリをクローンして、コードを動かしてみてください。

新しい環境のセットアップ

このチュートリアルを始める前に venv を使用して新しい仮装環境を構築します。
これにより他のプロジェクトとは独立して、パッケージの構成をきれいに保つことができます。

python3 -m venv env
source env/bin/acttivate

新しく構築した環境内にいるため、必要なパッケージをインストールします。

pip install django
pip install djangorestframework
pip install pygments  # コードのハイライトにこれを使います

この仮想環境から出るには、deactivate と入力してください。より詳細な情報はvenv documentationを確認してください。

はじめに

それではコーディングする準備が整ったので、新しくプロジェクトを作成しましょう。

cd ~
django-admin startproject tutorial
cd tutorial

新規プロジェクトの作成が完了したら、シンプルなWeb APIを作るためのアプリを作りましょう。

python manage.py startapp snippets

上記で新しく作成した snippets アプリと rest_framework アプリを INSTALLED_APPS に追加する必要があります。
それでは tutorial/settings.py を編集しましょう:

tutorial/settings.py
INSTALLED_APPS = [
    ...
    
    'rest_framework',
    'snippets',
]

これで準備は完了です。

作業するModelの作成

このチュートリアルでは、コードスニペットを保存するためのシンプルなSnippetモデルを作成するとこから始めます。snippets/models.py ファイルを編集してください。
補足: 良いプログラミングの習慣はコメントを書くことです。リポジトリの本チュートリアルのバージョンでコメントを見ることができますが、ここではコードのみに集中するためコメントは省略しています。

snippets/models.py
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ['created']

上記のコードを実装後、Snippetモデルの最初のマイグレーションを作成し、データベースを同期する必要があります。

python manage.py makemigrations snippets
python manage.py migrate snippets

✏️補足

Snippetモデル(snippets/models.py)で記述されているコードの一部を説明したいと思います。

Pygmentsという構文ハイライターライブラリからそれぞれ以下(コメント参照)をインポートしています。

from pygments.lexers import get_all_lexers # 言語の構文解析
from pygments.styles import get_all_styles # スタイル(色や見た目)

Pythonを例にした get_all_lexers() の戻り値は以下のようになるため、if item[1] で言語の有無を確認し、存在するもののみ LEXERS に代入します。
('Python', ['python', 'py'], ['*.py'], ['text/x-python'])
言語の正式名称, エイリアス, 対応する拡張子, 対応MINE type

LEXERS = [item for item in get_all_lexers() if item[1]]

LANGUAGE_CHOICES には、LEXERS からエイリアス(例: 'python')と 言語の正式名称(例: 'Python')のみを抽出し、それらをソートして代入します。
(sorted() 関数は、引数としてリストやタプルを受け取った場合、各要素の第1要素(この場合はエイリアスの 'python')を基準にソートします。)

LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])

STYLE_CHOICES には利用可能なスタイルをタプルのリストに変換し、代入しています。
get_all_styles() は 'default', 'emacs', 'friendly', 'colorful' のようなスタイル名(文字列)を順に返します。
そのため、各スタイル名を (item, item) の形でタプルにし、STYLE_CHOICES に追加しています。
このように1つの値を2つの要素に分けてタプルにしている理由は、
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) の choices 引数が、
「①内部に保存する値」と「②フォームや管理画面で表示されるラベル」のペアを必要とするためです。(LANGUAGE_CHOICES も同じ意図で2つの要素のタプルにしています)
今回は、スタイル名がそのまま表示名としても十分わかりやすいため、両方に同じ値を使っています。

STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])

Serializerクラスの作成

本チュートリアルでWeb APIを作成するにあたり、最初に行うべきことは、SnippetインスタンスをJSONなどの形式にシリアライズ(変換) および デシリアライズ(元に戻す) する方法を用意することです。
これは、Djangoのフォームに似た動作をする Serializer を定義することで実現できます。
snippets ディレクトリ内に serializers.py という名前のファイルを作成し、以下のコードを追加してください。

snippets/serializers.py
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


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)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        バリデーションが通ったデータをもとに、新しいSnippetインスタンスを作成して返します。
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        バリデーションが通ったデータをもとに、既存のSnippetインスタンスを更新して返します。
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

Serializerクラスの最初の部分では、シリアライズ/デシリアライズ されるフィールドを定義します。
create() と update()メソッドは、serializer.save() が呼び出されたときに、どのようにインスタンスが作成 または 更新されるかを定義します。

Serializerクラスは Django のフォームクラスと非常によく似ており、requiredmax_lengthdefaultなど、さまざまなフィールドに対するバリデーション用のフラグを持っています。

フィールドのフラグは、HTMLとしてレンダリングされる場合など、特定の状況においてSerializerがどのように表示されるべきかを制御することもできます。
上記の {'base_template': 'textarea.html'} というフラグは、Djangoのフォームクラスにおける widget=widgets.Textarea を指定するのと同じ意味です。
これらのフラグは、チュートリアルの後半で登場する browsable API(ブラウズ可能なAPI)において、表示方法を制御するのに特に役立ちます。

実は、後ほど説明する ModelSerializer クラスを使えばこれらのコードを書く手間を省くこともできるのですが、ここでは Serializer の定義を明示的に行うことにします。

✏️補足

Snippetモデル(snippets/models.py)で定義したLANGUAGE_CHOICES と STYLE_CHOICES をここでも choices に使用していますね。

class SnippetSerializer(serializers.Serializer):
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

SnippetモデルとSerializerクラスで使用用途の違いは以下になります。

SnippetモデルSerializerクラス
データベースに保存する値の制限APIリクエストのバリデーションを行う
Django 管理画面などで選択肢として表示させるためBrousable API(チュートリアル後半で使用)でのフォーム表示や選択肢の表示のため
モデルと無関係な独自のシリアライザを使う場合にも対応可能

また、create() と update() は、後述する Serializerオブジェクトの save() を呼んだときに、インスタンスをどのように「新規作成」または「更新」して保存するかを定義するメソッドになります。

create() ではバリデーションが通ったデータはvalidated_data という辞書型の変数に格納されます。この辞書はフィールド名をキーとして持つため、**validated_data とアンパックすることで、各フィールドに対応する値がキーワード引数として Snippet.objects.create() に渡され、モデルの新しいインスタンスが作成・保存されます。

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

update()メソッドには validated_data のほかに SnippetSerializer(instance, data=xx) のように instance も渡されます。
この instance には、以下のように Serializer を呼び出すときに第1引数として渡されたModelオブジェクトが入ります。
これは主に「更新(update)」処理を行いたいときに使います。

serializer = SnippetSerializer(snippet, data=data)

instance.xx = validated_data.get('xx', instance.xx) は、Modelオブジェクトの各フィールドを更新する処理です。
validated_data は辞書型なので、get()メソッドを使って、指定したキー(ここでは 'title')の値を取得しています。
もしそのキーが存在しない(更新データがない)場合は、代わりに既存の値(instance.title)を使って、元の値を維持するようにしています。

instance.title = validated_data.get('title', instance.title)

このようにして、更新用のデータが存在するものだけが書き換えられるようになっています。

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

Serializerの操作

チュートリアルを進める前に、シリアラザクラスの使い方について慣れておきましょう。それではDjangoシェルに入ってみましょう。

python manage.py shell

いくつかインポートを済ませたら、実際に操作するためのコードスニペットをいくつか作成しましょう。

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

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

これで、スニペットインスタンスをいくつか用意できました。それでは、これらから1つのインスタンスをシリアライズしてみましょう。

serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}

この時点で、ModelインスタンスをPythonが扱う基本的なデータ型に変換しました。シリアライズ処理を完了させるために、このデータをJSONに変換します。

content = JSONRenderer().render(serializer.data)
content
# b'{"id":2,"title":"","code":"print(\\"hello, world\\")\\n","linenos":false,"language":"python","style":"friendly"}'

デシリアライズも類似しており、まずはストリームをPythonの基本的なデータ型にパース(構文解析)して変換します。

import io

stream = io.BytesIO(content)
data = JSONParser().parse(stream)

そして、これら(data)のPythonのデータを 完全なModelインスタンス(フィールドに値がしっかり入ったインスタンス)として復元します。

serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'title': '', 'code': 'print("hello, world")', 'linenos': False, 'language': 'python', 'style': 'friendly'}
serializer.save()
# <Snippet: Snippet object>

このAPIがフォームを扱う流れに非常に似ていることに注目してください。この類似点は、Serializerを使ったViewの記述時にさらに明確になります。

Modelインスタンスに加えて、QuerySetをシリアライズすることも可能です。これを行うには、Serializerの引数に many=True を追加します。

serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [{'id': 1, 'title': '', 'code': 'foo = "bar"\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}, {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}, {'id': 3, 'title': '', 'code': 'print("hello, world")', 'linenos': False, 'language': 'python', 'style': 'friendly'}]

✏️補足

Serializerの操作のPythonシェルで行ったシリアライズとデシリアライズの流れは以下になります。

【シリアライズ】
・Snippetオブジェクト(モデルインスタンス)
    ↓
・Snippetオブジェクト
   # serializer = SnippetSerializer(snippet)
    ↓
・Pythonの辞書型データ
   # serializer.data
    ↓
・JSON

【デシリアライズ】
・JSON
    ↓
・Pythonの辞書型データ
   # data = JSONParser().parse(stream)
    ↓
・Serializerオブジェクト
   # serializer = SnippetSerializer(data=data)
    ↓
・Snippetオブジェクト(モデルインスタンス)

ModelSerializersの使用

SnippetSerializerクラスは Snippetモデルにも含まれている多くの情報を繰り返し定義しています。
これらのコードをもう少し簡潔にできたら理想的です。

Djangoが Formクラス と ModelFormクラスの両方を提供しているのと同様に、REST frameworkは Serializerクラス と ModelSerializerクラスの両方を提供しています。

それでは、ModelSerializerクラスを使ってSerializerをリファクタリングしてみましょう。
もう一度 snippets/serializers.pyファイルを開き、SnippetSerializerクラスを次のコードに置き換えます。

class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ['id', 'title', 'code', 'linenos', 'language', 'style']

Serializerの便利な特性のひとつは、Serializerインスタンス内のすべてのフィールドを簡単に確認できることです。

from snippets.serializers import SnippetSerializer
serializer = SnippetSerializer()
print(repr(serializer))
# SnippetSerializer():
#    id = IntegerField(label='ID', read_only=True)
#    title = CharField(allow_blank=True, max_length=100, required=False)
#    code = CharField(style={'base_template': 'textarea.html'})
#    linenos = BooleanField(required=False)
#    language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...
#    style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...

押さえとくべきポイントは、ModelSerializerクラスは何か特別なことをしているわけではなく、単にSerializerクラスを作るためのショートカットにすぎません:
・自動的に決定されるフィールドのセット
create() と update()のシンプルなデフォルト実装

✏️補足

ModelSerializer クラスを使うと、対象のModelに基づいてSerializerを簡潔に定義できます。
Meta クラスで model に対象のModelを指定し、fields にシリアライズ対象のフィールド名を列挙することで、必要なフィールドを自動的に定義してくれます。

さらに、本文でも説明されているように、create() や update() メソッドもModelに応じた適切な内容で自動的に実装されるため、自分でコードを書く必要はなく、省略することができます。

以下に ModelSerializer と Serializer を使った場合の実装の違いを示します。

# ModelSerializerクラスを使った実装
class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ['id', 'title', 'code', 'linenos', 'language', 'style']

# Serializerクラスを使った実装
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)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    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.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

ModelSerializer は多くの処理を自動化してくれるため、わざわざ自分でコードを書く必要がなく、Serializerをより少ない・簡潔なコードで定義できるというメリットがあります。そのため、実務でもよく使われることが多いそうです。

Serializer を使った通常の Django ビューの作成

それでは、新しいSerializerクラスを使ってAPIビューを書く方法を見ていきましょう。この時点ではREST frameworkの他の機能は使用しないため、通常のDjangoのViewを書きましょう。

snippets/views.pyファイルを編集して、以下の内容を追加しましょう。

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

このAPIのルート(最上位)には、既存のすべてのSnippetを一覧表示するか、新しいSnippetを作成するViewを配置します。

@csrf_exempt
def snippet_list(request):
    """
    すべてのコードスニペットを表示する、または新しいスニペットを作成する
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)

このViewに対して、CSRFトークンを持たないクライアントからも POSTできるようにしたいため、このビューには csrf_exempt を付けておく必要があります。これは通常であれば望ましいやり方ではありませんし、REST framework のビューは実際にはもっと適切な挙動をしますが、今の目的にはこれで十分です。

また、個別のSnippetに対応するViewも用意する必要があります。このViewは、Snippetの取得(retrieve)、更新(update)、削除(delete)に使用されます。

@csrf_exempt
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)

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

    elif request.method == 'PUT':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(snippet, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors, status=400)

    elif request.method == 'DELETE':
        snippet.delete()
        return HttpResponse(status=204)

最後に、これらのViewをルーティング(マッピング)する必要があります。
snippets/urls.pyファイルを作成してください:

from django.urls import path
from snippets import views

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

また、作成したSnippetアプリのURLを読み込むために、tutorial/urls.pyファイルにルートのURL設定を追加する必要があります。

from django.urls import path, include

urlpatterns = [
    path('', include('snippets.urls')),
]

現時点では、いくつかの例外的なケースに適切に対応できていないことに注意してください。例えば、不正なJSONを送信した場合や、Viewが対応していないHTTPメソッドでリクエストされた場合、最終的に「500 サーバーエラー」のレスポンスが返ってしまいます。それでも、今のところはこれで十分です。

✏️補足

ここではまず、今回インポートした下記ライブラリの説明をしたいと思います。

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

JsonResponseはJSON形式のレスポンスを返すためのクラスです。
例えば return JsonResponse(serializer.data, safe=False) では、シリアライズされたデータを第1引数に指定して、以下のようなJSON形式で返しています:

{'id': 1, 'title': 'sample_title', 'code': 'foo = "bar"\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}, {...}, ...

以下のコードのJsonResponse() で第2引数に safe=False を指定しているのは、serializer.data がリスト型)複数Snippetの一覧)だからです。
JsonResponse はデフォルトでは辞書型(dict)のみを許可するため、リストを返したい場合は「意図的にリストを返している」ということを safe=False で明示する必要があります。

from django.http import JsonResponse

def snippet_list(request):
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)
        ...

以下のコードの HttpResponse は、HTMLやプレーンテキストなどのレスポンスを返すための基本的なクラスです。
以下のように、Snippetが存在しない場合に 404 エラーを返すために使われています(DELETEメソッドの場合はSnippetを削除した後に、リクエストが成功して返すべきコンテンツがないことを明示するために使用しています):

from django.http import HttpResponse

def snippet_detail(request, pk):
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)
        ...

本文でも説明がありましたが。@csrf_exempt はDjangoのViewにCSRF(クロスサイトリクエストフォージェリ)保護を無効化するためのデコレーターです。このデコレーターを使うことで、そのViewに対してCSRFトークンの検証がスキップされるため、APIや外部からのリクエストを受け入れる場合に便利です。ただし、安全性に注意が必要です。

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def snippet_list(request):
    if request.method == 'GET':
        ...
    elif request.method == 'POST':
        ...

JSONParser は、JSON形式のデータをPythonの辞書型に変換するクラスです。ここでは、リクエストの POSTメソッドなどで送信されたJSONデータを辞書型データとして取り出すために使用しています。

from rest_framework.parsers import JSONParser

def snippet_list(request):
    if request.method == 'GET':
        ...
    elif request.method == 'POST':
        data = JSONParser().parse(request)

また、以下のコードでは、Snippetモデルと作成した SnippetSerializerクラスを使用し、データのシリアライズやModelとのやり取りを行えるようにしています。

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

最初のWeb APIを試す

これで、Snippetを提供するサンプルサーバーを起動できるようになりました。
シェルを終了しましょう。

quit()

次にDjangoの開発サーバーを起動しましょう。

python manage.py runserver

Validating models...

0 errors found
Django version 5.0, using settings 'tutorial.settings'
Starting Development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

別のターミナルウィンドウでサーバーをテストすることができます。

APIのテストには、curl や httpie を使用できます。httpie はPythonで書かれた、使いやすいHTTPクライアントです。それでは、これをインストールしてみましょう。

httpie は pipを使ってインストールできます:

pip install httpie

最後に全てのSnippetの一覧を取得してみましょう:

http GET http://127.0.0.1:8000/snippets/ --unsorted

HTTP/1.1 200 OK
...
[
    {
        "id": 1,
        "title": "",
        "code": "foo = \"bar\"\n",
        "linenos": false,
        "language": "python",
        "style": "friendly"
    },
    {
        "id": 2,
        "title": "",
        "code": "print(\"hello, world\")\n",
        "linenos": false,
        "language": "python",
        "style": "friendly"
    },
    {
        "id": 3,
        "title": "",
        "code": "print(\"hello, world\")",
        "linenos": false,
        "language": "python",
        "style": "friendly"
    }
]

もしくは、IDを指定して特定のSnippetを取得することもできます:

http GET http://127.0.0.1:8000/snippets/2/ --unsorted

HTTP/1.1 200 OK
...
{
    "id": 2,
    "title": "",
    "code": "print(\"hello, world\")\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

同様に、これらのURLにWebブラウザでアクセスすることで、同じJSONを表示することができます。

✏️補足

httpie は、APIと簡単にやり取りできるコマンドラインのHTTPクライアントツールになります。

現状の確認

ここまでは順調です。現在、DjangoのForms APIによく似たシリアライゼーションAPIと、いくつかの通常のDjangoのViewができています。

現時点でAPI Viewは、JSONレスポンスを返す以外に特別なことはしていませんし、エラーハンドリングの細かいケースにもまだ改善の余地がありますが、ひとまず動作するWeb APIが完成しています。

チュートリアルのパート2では、ここからどのように改善していけるかを見ていきましょう。

💡 まとめ:Tutorial 1 を終えて

ここからは、筆者(野崎)による今回の振り返りまとめです。

第1回目となる今回は、Django REST frameworkの基本である**Serialization(シリアライズ)**について学習しました。

  • Modelの作成: データを保存する器の準備
  • Serializerの定義: ModelとJSONを相互変換する仕組みの構築
  • Django Viewの実装: 実際にリクエストを受け取り、JSONをレスポンスする流れ

普段使っているDjangoの「Form」と非常に似た感覚で、APIが構築できることを実感できたのではないでしょうか。私は最初「シリアライズ」という言葉に難しさを感じていましたが、このチュートリアルを通して「データの翻訳機」のようなものだと理解できました!

現時点ではまだ「通常のDjango View」を使って実装していますが、次回のパート2では、DRFの真骨頂であるRequest/ResponseオブジェクトAPI Viewを導入し、さらにコードをスマートにリファクタリングしていきます!

コメント