Tutorial 1: Serialization
はじめに
本記事は、Django REST framework の公式チュートリアルTutorial 1: Serializationの内容をもとに、和訳および補足解説を行ったものです。
基本的にはチュートリアルの翻訳を軸に構成しており、✏️補足
の箇所では、各コードセクションの補足や内部処理の解説を備忘録的に記載しています。
他のチュートリアル記事もあわせて読みたい方は、以下のまとめ記事からご覧いただけます👇
DRF(Django REST framework)公式チュートリアルを日本語でまとめてみた【全6回】
それでは、本チュートリアルを始めましょう。
イントロダクション
このチュートリアルでは、シンプルな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
を編集しましょう:
INSTALLED_APPS = [
...
'rest_framework',
'snippets',
]
これで準備は完了です。
作業するModelの作成
このチュートリアルでは、コードスニペットを保存するためのシンプルなSnippetモデルを作成するとこから始めます。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
という名前のファイルを作成し、以下のコードを追加してください。
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 のフォームクラスと非常によく似ており、required
、max_length
、default
など、さまざまなフィールドに対するバリデーション用のフラグを持っています。
フィールドのフラグは、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では、ここからどのように改善していけるかを見ていきましょう。