#django REST framework チュートリアルの Google日本語翻訳 ( Tutorial 1: Serializatio
Ref
<h1 id="tutorial-1-serialization"> <a class="toclink" href="#tutorial-1-serialization">チュートリアル1:直列化</a> </h1><h2 id="introduction"> <a class="toclink" href="#introduction">前書き</a> </h2><p>このチュートリアルでは、Web APIを強調する単純なペーストビンコードの作成について説明します。その過程で、RESTフレームワークを構成するさまざまなコンポーネントを紹介し、すべてがどのように組み合わさっているかについての包括的な理解を得ます。 </p><p>チュートリアルはかなり詳しく書かれているので、始める前におそらくあなたはクッキーとあなたの大好きなコップを手に入れるべきです。簡単な概要を知りたいだけの場合は、代わりに<a href="../quickstart/">クイックスタートの</a>ドキュメントを参照してください。 </p><hr /><p> <strong>注</strong> :このチュートリアルのコードは、GitHubの<a href="https://github.com/encode/rest-framework-tutorial">encode / rest-framework-tutorial</a>リポジトリにあります。完成した実装は、テスト用のサンドボックス版としてオンラインでも<a href="https://restframework.herokuapp.com/">入手できます</a> 。 <a href="https://restframework.herokuapp.com/">こちら</a>から<a href="https://restframework.herokuapp.com/">入手できます</a> 。 </p><hr /><h2 id="setting-up-a-new-environment"> <a class="toclink" href="#setting-up-a-new-environment">新しい環境を設定する</a> </h2><p>他のことをする前に、 <a href="http://www.virtualenv.org/en/latest/index.html">virtualenv</a>を使って新しい仮想環境を作成します。これは私達のパッケージ構成が私達が取り組んでいる他のどのプロジェクトからもきちんと隔離されて保たれるのを確実にするでしょう。 </p><pre><code>virtualenv env
source env/bin/activate
</code></pre> <p>これでvirtualenv環境に入ったので、パッケージ要件をインストールできます。 </p><pre><code>pip install django
pip install djangorestframework
pip install pygments # We'll be using this for the code highlighting
</code></pre> <p> <strong>注:</strong> virtualenv環境をいつでも終了するには、 <code>deactivate</code> 。詳しくは<a href="http://www.virtualenv.org/en/latest/index.html">virtualenvのドキュメントを</a>参照してください。 </p><h2 id="getting-started"> <a class="toclink" href="#getting-started">入門</a> </h2><p>さて、これでコーディングを始める準備が整いました。はじめに、作業する新しいプロジェクトを作成しましょう。 </p><pre><code>cd ~
django-admin startproject tutorial
cd tutorial
</code></pre> <p>これが完了したら、単純なWeb APIを作成するために使用するアプリを作成できます。 </p><pre><code>python manage.py startapp snippets
</code></pre> <p>新しい<code>snippets</code>アプリと<code>rest_framework</code>アプリを<code>INSTALLED_APPS</code>に追加する必要があります。 <code>tutorial/settings.py</code>ファイルを編集しましょう。 </p><pre><code>INSTALLED_APPS = (
...
'rest_framework',
'snippets.apps.SnippetsConfig',
)
</code></pre> <p>さて、私たちはロールの準備ができています。 </p><h2 id="creating-a-model-to-work-with"> <a class="toclink" href="#creating-a-model-to-work-with">使用するモデルを作成する</a> </h2><p>このチュートリアルの目的のために、コードスニペットを格納するために使用される単純な<code>Snippet</code>モデルを作成することから始めます。さあ、 <code>snippets/models.py</code>ファイルを編集してください。注:良いプログラミング方法にはコメントが含まれます。このチュートリアルコードのリポジトリ版にはありますが、ここではコード自体に焦点を絞るために省略しています。 </p><pre><code>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',)
</code></pre> <p>また、スニペットモデルの初期移行を作成し、データベースを初めて同期する必要があります。 </p><pre><code>python manage.py makemigrations snippets
python manage.py migrate
</code></pre> <h2 id="creating-a-serializer-class"> <a class="toclink" href="#creating-a-serializer-class">シリアライザクラスの作成</a> </h2><p>私たちがWeb APIを始めるために最初に必要なことは、スニペットインスタンスを<code>json</code>ような表現にシリアライズしデシリアライズする方法を提供することです。 Djangoのフォームと非常によく似た働きをするシリアライザを宣言することでこれを実現できます。 <code>snippets</code>ディレクトリに<code>serializers.py</code>という名前のファイルを作成し、以下を追加します。 </p><pre><code>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):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Snippet.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the 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
</code></pre> <p>シリアライザクラスの最初の部分は、シリアライズ/デシリアライズされるフィールドを定義します。 <code>create()</code>および<code>update()</code>メソッドは、 <code>serializer.save()</code>呼び出すときに、完全に準備されたインスタンスがどのように作成または変更されるかを定義します。 </p><p>シリアライザクラスはDjango <code>Form</code>クラスと非常によく似ており、 <code>required</code> 、 <code>max_length</code> 、 <code>default</code>などのさまざまなフィールドに同様の検証フラグが含まれてい<code>default</code> 。 </p><p>フィールドフラグは、HTMLへのレンダリング時など、特定の状況でのシリアライザの表示方法も制御できます。上記の<code>{'base_template': 'textarea.html'}</code>フラグはDjango <code>Form</code>クラスで<code>widget=widgets.Textarea</code>を使うのと同じです。チュートリアルの後半で見るように、これはブラウズ可能なAPIがどのように表示されるべきかを制御するのに特に役に立ちます。 </p><p> <code>ModelSerializer</code>するように、 <code>ModelSerializer</code>クラスを使用して実際に時間を節約することもできますが、ここではシリアライザ定義を明示的にしておきます。 </p><h2 id="working-with-serializers"> <a class="toclink" href="#working-with-serializers">シリアライザの使用</a> </h2><p>先に進む前に、新しいSerializerクラスを使用する方法について説明します。 Djangoシェルに入りましょう。 </p><pre><code>python manage.py shell
</code></pre> <p>さて、いくつかのインポートが邪魔にならなくなったら、それを処理するためのコードスニペットをいくつか作成しましょう。 </p><pre><code>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()
</code></pre> <p>これでいくつかのスニペットインスタンスを再生できます。これらのインスタンスの1つを直列化してみましょう。 </p>
<pre><code>serializer = SnippetSerializer(snippet)
serializer.data
{'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}
</code></pre> <p>この時点で、モデルインスタンスをPythonのネイティブデータ型に変換しました。直列化プロセスを完成させるために、データを<code>json</code>レンダリングします。 </p><pre><code>content = JSONRenderer().render(serializer.data)
content
b'{"id": 2, "title": "", "code": "print(\"hello, world\")\n", "linenos": false, "language": "python", "style": "friendly"}'
</code></pre> <p>逆シリアル化も同様です。まず、ストリームをPythonのネイティブデータ型に解析します。 </p><pre><code>import io
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
</code></pre> <p> ...そして、それらのネイティブデータ型を完全に移入されたオブジェクトインスタンスに復元します。 </p><pre><code>serializer = SnippetSerializer(data=data)
serializer.is_valid()
True
serializer.validated_data
OrderedDict([('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
<Snippet: Snippet object>
</code></pre> <p> APIがフォームを操作するのに似ていることに注目してください。シリアライザを使用するビューを書き始めると、類似性がさらに明らかになります。 </p><p>モデルインスタンスの代わりにクエリセットをシリアル化することもできます。そのためには、シリアライザの引数に<code>many=True</code>フラグを追加するだけです。 </p><pre><code>serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
[OrderedDict([('id', 1), ('title', ''), ('code', 'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', ''), ('code', 'print("hello, world")'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]
</code></pre> <h2 id="using-modelserializers"> <a class="toclink" href="#using-modelserializers">ModelSerializerを使用する</a> </h2><p>私たちの<code>SnippetSerializer</code>クラスは<code>Snippet</code>モデルにも含まれているたくさんの情報を複製しています。コードをもう少し簡潔にしておくといいでしょう。 </p><p> Djangoが<code>Form</code>クラスと<code>ModelForm</code>クラスの両方を提供するのと同じように、RESTフレームワークは<code>Serializer</code>クラスと<code>ModelSerializer</code>クラスの両方を<code>ModelSerializer</code>ます。 </p><p> <code>ModelSerializer</code>クラスを使った<code>ModelSerializer</code>リファクタリングを見てみましょう。ファイル<code>snippets/serializers.py</code>もう一度開き、 <code>SnippetSerializer</code>クラスを次のように置き換えます。 </p><pre><code>class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
</code></pre> <p>シリアライザの優れた特性の1つは、その表現を印刷することによって、シリアライザインスタンス内のすべてのフィールドを調べることができるということです。 <code>python manage.py shell</code>でDjangoシェルを開き、以下を試してください。 </p><pre><code>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')...
</code></pre> <p> <code>ModelSerializer</code>クラスは特に魔法のようなことはしないことを覚えておくことが重要です。それらはシリアライザクラスを作成するための単なるショートカットです。 </p><ul><li>自動的に決定されたフィールドのセット。 </li><li> <code>create()</code>および<code>update()</code>メソッドの単純なデフォルト実装</li></ul><h2 id="writing-regular-django-views-using-our-serializer"> <a class="toclink" href="#writing-regular-django-views-using-our-serializer">シリアライザを使って通常のDjangoビューを書く</a> </h2><p>新しいSerializerクラスを使用してAPIビューを作成する方法を見てみましょう。現時点では、RESTフレームワークのその他の機能は一切使用しません。通常のDjangoビューとしてビューを作成します。 </p><p> <code>snippets/views.py</code>ファイルを編集して、以下を追加してください。 </p><pre><code>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
</code></pre> <p>私たちのAPIの根底にあるのは、既存のすべてのスニペットを一覧表示すること、または新しいスニペットを作成することをサポートするビューです。 </p><pre><code>@csrf_exempt
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
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)
</code></pre> <p> CSRFトークンを持たないクライアントからこのビューにPOSTできるようにしたいので、ビューを<code>csrf_exempt</code>としてマークする必要があります。これはあなたが通常やりたいことではありません、そしてRESTフレームワークビューは実際にこれより賢明な振る舞いを使用します、しかしそれは今私たちの目的のためにするでしょう。 </p><p>個々のスニペットに対応し、スニペットの取得、更新、削除に使用できるビューも必要です。 </p><pre><code>@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)
</code></pre> <p>最後に、これらの見解を結び付ける必要があります。 <code>snippets/urls.py</code>ファイルを作成します。 </p><pre><code>from django.urls import path
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>/', views.snippet_detail),
]
</code></pre> <p>スニペットアプリケーションのURLを含めるには、 <code>tutorial/urls.py</code>ファイルにあるルートのurlconfも配線する必要があります。 </p><pre><code>from django.urls import path, include
urlpatterns = [
path('', include('snippets.urls')),
]
</code></pre> <p>現時点で適切に対処していないエッジケースがいくつかあることは注目に値します。不正な形式の<code>json</code>を送信した場合、またはビューが処理しないメソッドで要求が行われた場合は、500「サーバーエラー」の応答が返されます。それでも、これは今のところします。 </p><h2 id="testing-our-first-attempt-at-a-web-api"> <a class="toclink" href="#testing-our-first-attempt-at-a-web-api">Web APIでの最初の試みをテストする</a> </h2><p>これで、スニペットを扱うサンプルサーバーを起動できます。 </p><p>シェルを終了します... </p><pre><code>quit()
</code></pre> <p> ...そしてDjangoの開発サーバーを起動します。 </p><pre><code>python manage.py runserver
Validating models...
0 errors found
Django version 1.11, using settings 'tutorial.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
</code></pre> <p>別の端末ウィンドウで、サーバーをテストできます。 </p><p> <a href="https://curl.haxx.se/">curl</a>または<a href="https://github.com/jakubroztocil/httpie#installation">httpie</a>を使ってAPIをテストできます。 HttpieはPythonで書かれたユーザーフレンドリーなhttpクライアントです。それをインストールしましょう。 </p><p>あなたはpipを使ってhttpieをインストールすることができます。 </p><pre><code>pip install httpie
</code></pre> <p>最後に、すべてのスニペットのリストを取得できます。 </p><pre><code>http http://127.0.0.1:8000/snippets/
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"
}
]
</code></pre> <p>あるいは、そのIDを参照することで特定のスニペットを取得できます。 </p><pre><code>http http://127.0.0.1:8000/snippets/2/
HTTP/1.1 200 OK
...
{
"id": 2,
"title": "",
"code": "print("hello, world")\n",
"linenos": false,
"language": "python",
"style": "friendly"
}
</code></pre> <p>同様に、WebブラウザでこれらのURLにアクセスしても同じJSONを表示できます。 </p>
Original by Github issue
チャットメンバー募集
何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。
公開日時
2019-05-06
Discussion