1 - Serialization
チュートリアル1:シーケンス化
紹介する
このチュートリアルでは、簡単な収録コードのハイライト表示を作成するWeb APIについて説明します.プロセス全体では、REST framewoekを構成する各コンポーネントについて説明し、各コンポーネントがどのように一緒に動作しているかを全面的に理解します.
このチュートリアルはかなり深いので、始める前にクッキーと一番好きなビールを用意しなければなりません.すばやく参照したい場合は、クイック入門ドキュメントを使用する必要があります.
注:このチュートリアルのコードは、Githubのtomchristie/rest-framework-tutorialリポジトリで入手できます.完全なインプリメンテーションは、オンラインで砂箱バージョンとしてテストすることもできます.
新しい環境を構築する
他のことをする前にvirtualenvで新しい仮想環境を作成します.これにより、私たちのパッケージ構成が、私たちが処理している他のプロジェクトと良好に隔離されていることが保証されます.
virtualenv環境では、必要なパッケージをインストールできます.
注意:virtualenv環境を随時終了するには、
スタート
では、コードを書き始めます.まず、新しいプロジェクトを作成しましょう.
上記の手順を完了すると、簡単なWeb APIを作成するためのアプリケーションを作成できます.
新規
はい、私たちの準備は終わりました.
モデルの作成
このチュートリアルの目的を達成するために、コードクリップを格納するための簡単な
また、コードセグメントモデルの初期移行(initial migration)を作成し、データベースを初めて同期する必要があります.
シーケンス化クラスの作成
Web APIの使用を開始する最初のことは、コードフラグメントインスタンスを表示形式(例えば
シーケンサクラスの第1部では、シーケンサ/逆シーケンサを取得するフィールドを定義します.
シーケンサクラスはDjango
フィールドフラグは、HTMLをレンダリングするなど、serializerが場合によってはどのように表示されるかを制御することもできます.上の
実際には
Serializersの使用
私たちがさらに理解する前に、私たちの新しい
では、いくつかのモジュールをインポートし、いくつかのコードクリップを作成して処理し始めました.
いくつかの使用可能なフラグメントインスタンスがあります.シーケンス化されたインスタンスの1つを見てみましょう.
このとき,モデルインスタンスをPythonオリジナルデータ型に変換する.シーケンス化プロセスを完了するには、データを
逆シーケンス化は似ています.まず、Pythonのオリジナルデータ型としてストリームを解析します.
...その後、これらのオリジナルデータ型を通常のオブジェクトインスタンスに復元します.
APIの動作形式とフォーム(forms)がどのように似ているかに注意してください.シーケンス化クラスを使用してビューを記述し始めると、類似性がより顕著になります.
モデルインスタンスの代わりにクエリーセットをシーケンス化することもできます.このため、シーケンス化パラメータに
ModelSerializersの使用
我々の
Djangoが提供した
シーケンス化プログラムの素晴らしいプロパティは、その構造を印刷することで、シーケンス化インスタンスのすべてのフィールドをチェックすることです.
覚えておいてフィールドのセットを自動的に決定する.(クラス属性の再定義は不要) デフォルトで簡単に実現される
我々のSerializerを使用して、従来のDjangoビューを作成します.
新しいSerializerクラスを使用してAPIビューを作成する方法を見てみましょう.現在、REST frameworkの他の機能は使用されていません.通常のDjangoビューのみを作成します.
我々のAPIのルートビューは、すべての既存のsnippetをリストするか、新しいsnippetを作成することをサポートします.
なお、CSRFトークンを持たないクライアントPOSTをこのビューに表示することを望むため、このビューを
また、単一のsnippetに対応するビューが必要であり、snippetの取得、更新、または削除に使用できます.
最後に、これらのビューを接続する必要があります.作成
また、snippetsアプリケーションのURLsを含むroot urlconfを
注目すべきは、まだいくつかのエッジケースを処理していないことです.フォーマットが間違っている
Web APIでの最初のアクセスをテスト
次に、snippetsのサーバを起動します.
終了...
...Djangoの開発サーバを起動します.
別のターミナルウィンドウを開き、サーバをテストできます.
curlまたはhttpieを使用して、APIをテストすることができます.HttpieはPythonで作成されたユーザーに優しいhttpクライアントです.インストールしましょう.
pipを使用してhttpieをインストールできます.
最後に、すべてのsnippetのリストを得ることができます.
あるいは、idを参照することで、特定のsnippetを取得することができます.
同様に、WebブラウザでこれらのURLにアクセスすることで、同じ
今どこにいるの?
これまで、DjangoのForms APIと非常に似たシーケンス化APIと、いくつかの従来のDjangoビューを持っていました.
サービス
このチュートリアルの第2部では、これらのことを改善する方法について説明します.
紹介する
このチュートリアルでは、簡単な収録コードのハイライト表示を作成するWeb APIについて説明します.プロセス全体では、REST framewoekを構成する各コンポーネントについて説明し、各コンポーネントがどのように一緒に動作しているかを全面的に理解します.
このチュートリアルはかなり深いので、始める前にクッキーと一番好きなビールを用意しなければなりません.すばやく参照したい場合は、クイック入門ドキュメントを使用する必要があります.
注:このチュートリアルのコードは、Githubのtomchristie/rest-framework-tutorialリポジトリで入手できます.完全なインプリメンテーションは、オンラインで砂箱バージョンとしてテストすることもできます.
新しい環境を構築する
他のことをする前にvirtualenvで新しい仮想環境を作成します.これにより、私たちのパッケージ構成が、私たちが処理している他のプロジェクトと良好に隔離されていることが保証されます.
virtualenv env
source env/bin/activate
virtualenv環境では、必要なパッケージをインストールできます.
pip install django
pip install djangorestframework
pip install pygments #
注意:virtualenv環境を随時終了するには、
deactivate
を入力するだけです.詳細については、virtualenvドキュメントを参照してください.スタート
では、コードを書き始めます.まず、新しいプロジェクトを作成しましょう.
cd ~
django-admin.py startproject tutorial
cd tutorial
上記の手順を完了すると、簡単なWeb APIを作成するためのアプリケーションを作成できます.
python manage.py startapp snippets
新規
snippets
アプリケーションとrest_framework
アプリケーションをINSTALLED_APPS
に追加する必要があります.編集tutorial/settings.py
ファイル:INSTALLED_APPS = (
...
'rest_framework',
'snippets.apps.SnippetsConfig',
)
はい、私たちの準備は終わりました.
モデルの作成
このチュートリアルの目的を達成するために、コードクリップを格納するための簡単な
Snippet
モデルの作成を開始します.そして編集を続けますsnippets/models.py
ファイル.注意:良いプログラミング方法には、コメントの追加が含まれます.このチュートリアル・コードのリポジトリ・バージョンでは見つけることができますが、コード自体に焦点を当てるために無視します.from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
# pygments
LEXERS = [item for item in get_all_lexers() if item[1]]
# pygments
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
# pygments
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
# Create your models here.
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',)
また、コードセグメントモデルの初期移行(initial migration)を作成し、データベースを初めて同期する必要があります.
python manage.py makemigrations snippets
python manage.py migrate
シーケンス化クラスの作成
Web APIの使用を開始する最初のことは、コードフラグメントインスタンスを表示形式(例えば
json
)にシーケンス化および逆シーケンス化する方法を提供することである.Django formsによく似たシーケンス化器(serializers)を宣言することで実現できる.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
シーケンサクラスの第1部では、シーケンサ/逆シーケンサを取得するフィールドを定義します.
create()
およびupdate()
メソッドは、呼び出しserializer.save()
のときに完全なインスタンスを作成および変更する方法を定義します.シーケンサクラスはDjango
Form
クラスと非常に類似しており、各種フィールドに類似の検証フラグ、例えばrequired
、max_length
およびdefault
が含まれている.フィールドフラグは、HTMLをレンダリングするなど、serializerが場合によってはどのように表示されるかを制御することもできます.上の
{'base_template': 'textarea.html'}
フラグはDjangoForm
クラスで使用widget=widgets.Textarea
と同等です.これは、ブラウズ可能なAPIの表示方法を制御するのに特に役立ちます.このチュートリアルの後で説明します.実際には
ModelSerializer
クラスを使用することで時間を節約できますが、後で見ますが、明確に定義したserializer
を使用します.Serializersの使用
私たちがさらに理解する前に、私たちの新しい
Serializer
クラスを熟知します.Django shellに入りましょう.python manage.py shell
では、いくつかのモジュールをインポートし、いくつかのコードクリップを作成して処理し始めました.
(env) fang@ubuntu:~/django_rest_framework/tutorial$ python manage.py shell
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 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"
')
>>> snippet.save()
>>>
>>> snippet = Snippet(code='print "hello, world"
')
>>> snippet.save()
>>>
いくつかの使用可能なフラグメントインスタンスがあります.シーケンス化されたインスタンスの1つを見てみましょう.
>>> serializer = SnippetSerializer(snippet)
>>> serializer.data
{'language': 'python', 'code': 'print "hello, world"
', 'style': 'friendly', 'id': 2, 'linenos': False, 'title': ''}
>>>
このとき,モデルインスタンスをPythonオリジナルデータ型に変換する.シーケンス化プロセスを完了するには、データを
json
にレンダリングします.>>> content = JSONRenderer().render(serializer.data)
>>> content
b'{"id":2,"title":"","code":"print \\"hello, world\\"\
","linenos":false,"language":"python","style":"friendly"}'
>>>
逆シーケンス化は似ています.まず、Pythonのオリジナルデータ型としてストリームを解析します.
>>> from django.utils.six import BytesIO
>>>
>>> stream = BytesIO(content)
>>> data = JSONParser().parse(stream)
>>> data
{'language': 'python', 'code': 'print "hello, world"
', 'style': 'friendly', 'id': 2, 'linenos': False, 'title': ''}
>>>
...その後、これらのオリジナルデータ型を通常のオブジェクトインスタンスに復元します.
>>> serializer = SnippetSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('title', ''), ('code', 'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
>>> serializer.save()
<Snippet: Snippet object (3)>
>>>
APIの動作形式とフォーム(forms)がどのように似ているかに注意してください.シーケンス化クラスを使用してビューを記述し始めると、類似性がより顕著になります.
モデルインスタンスの代わりにクエリーセットをシーケンス化することもできます.このため、シーケンス化パラメータに
many = True
フラグを追加するだけです.>>> serializer = SnippetSerializer(Snippet.objects.all(), many=True)
>>> serializer.data
[OrderedDict([('id', 1), ('title', ''), ('code', 'foo = "bar"
'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', ''), ('code', 'print "hello, world"
'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', ''), ('code', 'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]
>>>
ModelSerializersの使用
我々の
SnippetSerializer
クラスではSnippet
モデルに含まれる多くの情報が重複している.コードを簡潔に保つことができれば、もっといいです.Djangoが提供した
Form
クラスとModelForm
クラスのように、REST frameworkはSerializer
クラスとModelSerializer
クラスを含む.ModelSerializer
クラスを使用してシーケンス化クラスを再構築してみましょう.snippets/serializers.py
ファイルを再度開き、SnippetSerializer
クラスを以下に置き換えます.class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
シーケンス化プログラムの素晴らしいプロパティは、その構造を印刷することで、シーケンス化インスタンスのすべてのフィールドをチェックすることです.
>>> from snippets.serializers import SnippetSerializer
>>> serializer = SnippetSerializer()
>>> print(repr(serializer))
SnippetSerializer():
id = IntegerField(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=[('abap', 'ABAP'), ('abnf', 'ABNF'), ('ada', 'Ada'), ..., ('zephir', 'Zephir')], default='python')
style = ChoiceField(choices=[('abap', 'abap'), ('algol', 'algol'), ('algol_nu', 'algol_nu'), ..., ('xcode', 'xcode')], default='friendly')
>>>
覚えておいて
ModelSerializer
クラスは特に不思議なことはしません.シーケンス化器クラスを作成するショートカットにすぎません.create()
およびupdate()
メソッド.我々のSerializerを使用して、従来のDjangoビューを作成します.
新しいSerializerクラスを使用してAPIビューを作成する方法を見てみましょう.現在、REST frameworkの他の機能は使用されていません.通常のDjangoビューのみを作成します.
snippets/views.py
ファイルを編集し、以下の内容を追加します.from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
我々のAPIのルートビューは、すべての既存のsnippetをリストするか、新しいsnippetを作成することをサポートします.
@csrf_exempt
def snippet_list(request):
"""
snippet, 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)
なお、CSRFトークンを持たないクライアントPOSTをこのビューに表示することを望むため、このビューを
csrf_exempt
とマークする必要がある.これはあなたが通常したいことではありません.REST frameworkビューは実際にはこれよりも実用的な動作ですが、私たちの目的を達成するのに十分です.また、単一のsnippetに対応するビューが必要であり、snippetの取得、更新、または削除に使用できます.
@csrf_exempt
def snippet_detail(request, pk):
"""
, 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)
最後に、これらのビューを接続する必要があります.作成
snippets/urls.py
ファイル:from django.conf.urls import url
from snippets import views
urlpatterns = [
url(r'^snippets/$', views.snippet_list),
url(r'^snippets/(?P[0-9]+)/$' , views.snippet_detail),
]
また、snippetsアプリケーションのURLsを含むroot urlconfを
tutorial/urls.py
ファイルに接続する必要があります.from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('snippets.urls')),
]
注目すべきは、まだいくつかのエッジケースを処理していないことです.フォーマットが間違っている
json
を送信したり、ビューで処理しない方法で要求を発行したりすると、最終的に500「server error」の応答が得られます.とにかく、今私たちはしばらくそうします.Web APIでの最初のアクセスをテスト
次に、snippetsのサーバを起動します.
終了...
quit()
...Djangoの開発サーバを起動します.
(env) fang@ubuntu:~/django_rest_framework/tutorial$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
June 13, 2018 - 10:17:11
Django version 2.0.6, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
別のターミナルウィンドウを開き、サーバをテストできます.
curlまたはhttpieを使用して、APIをテストすることができます.HttpieはPythonで作成されたユーザーに優しいhttpクライアントです.インストールしましょう.
pipを使用してhttpieをインストールできます.
pip install httpie
最後に、すべてのsnippetのリストを得ることができます.
(env) fang@ubuntu:~/django_rest_framework/tutorial$ http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
Content-Length: 352
Content-Type: application/json
Date: Wed, 13 Jun 2018 10:23:58 GMT
Server: WSGIServer/0.2 CPython/3.5.2
X-Frame-Options: SAMEORIGIN
[
{
"code": "foo = \"bar\"
",
"id": 1,
"language": "python",
"linenos": false,
"style": "friendly",
"title": ""
},
{
"code": "print \"hello, world\"
",
"id": 2,
"language": "python",
"linenos": false,
"style": "friendly",
"title": ""
},
{
"code": "print \"hello, world\"",
"id": 3,
"language": "python",
"linenos": false,
"style": "friendly",
"title": ""
}
]
あるいは、idを参照することで、特定のsnippetを取得することができます.
(env) fang@ubuntu:~/django_rest_framework/tutorial$ http http://127.0.0.1:8000/snippets/2/
HTTP/1.1 200 OK
Content-Length: 119
Content-Type: application/json
Date: Wed, 13 Jun 2018 10:25:50 GMT
Server: WSGIServer/0.2 CPython/3.5.2
X-Frame-Options: SAMEORIGIN
{
"code": "print \"hello, world\"
",
"id": 2,
"language": "python",
"linenos": false,
"style": "friendly",
"title": ""
}
同様に、WebブラウザでこれらのURLにアクセスすることで、同じ
json
を表示することができます.今どこにいるの?
これまで、DjangoのForms APIと非常に似たシーケンス化APIと、いくつかの従来のDjangoビューを持っていました.
サービス
json
応答に加えて、APIビューでは現在特別なことは行われておらず、クリーンアップしたいエラー処理のエッジもありますが、通常動作しているWeb APIです.このチュートリアルの第2部では、これらのことを改善する方法について説明します.