Django REST FrameWork中国語教程1:シーケンス化

15164 ワード

紹介する
このチュートリアルでは、簡単なPasteBin 1コードでハイライトされたWeb APIについて説明します.プロセス全体で、REST frameworkの各構成部品を一つ一つ紹介し、コンポーネント間がどのように統合されているかを全面的に理解させます.
このチュートリアルは少し深いので、始める前に、クッキーを何枚か必要として、お気に入りの飲み物を1杯食べながら見るかもしれません.クイック・スタート・ドキュメントに移動するには、クイック・スタート・ドキュメントに移動します.
注:このチュートリアルのコードは、GitHubのtomchristie/rest-framework-tutorialリポジトリにあります.完成した実装もオンラインで砂箱バージョンとしてテストされ、ここで見つけることができます.
新しい環境を構築する
私たちが何かをする前にvirtualenvを使用して新しい仮想環境を作成します.これにより、パッケージ構成が他のプロジェクトと良好に隔離されていることが保証されます.
virtualenv
envsource env/bin/activate

これでvirtualenv環境に入り、必要なソフトウェアサポートパッケージのインストールを開始できます.
pip install django
pip install djangorestframework
pip install pygments  #               
注意:virtualenv環境をいつでも終了するには、deactivateを入力します.詳細については、virtualenvドキュメントを参照してください.
開始の準備
はい、コードを用意しました.まず、新しいプロジェクト(project)を作成して処理しましょう.
cd ~
django-admin.py startproject tutorial
cd tutorial

その後、appアプリケーションを作成して、簡単なWeb APIを作成することができます.
python manage.py startapp snippets

新しいsnippetsアプリケーションとrest_frameworkアプリケーションをINSTALLED_に追加APPS. tutorial/settingsを編集します.pyファイル:
INSTALLED_APPS = (
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
)

Django<1.9を使用する場合は、snippetsを交換する必要があります.apps.SnippetsConfigにはsnippetsがあります.
はい、準備はできました.
使用可能なモデルの作成(model)
チュートリアルの設計を考慮して、まず簡単なSnippetモデルを作成します.関連コードを格納し、snippets/models.pyファイルを編集します.注意:良いプログラミングの実践には注釈があります.このチュートリアルのサンプルコードではコメントを見つけることができますが、ここではコメントを省略します.
Python
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モデルのデータのテーブルを作成し、モデルをデータベースに同期し、初期の移行(migration)を実現する必要があります.
python manage.py makemigrations snippets
python manage.py migrate

シーケンス化Serializerクラスの作成
我々のWeb APIは、コードフラグメントのインスタンス(instances)にシーケンス化および逆シーケンス化の経路を提供し、jsonのような表現形式に変換できるようにすることから始まる.Djangoフォーム(form)の動作と同様に、宣言シーケンサ(serializer)を使用して実現できます.snippetsパスの下で、ファイルserializers.pyを作成し、以下の内容を指定します.
Python
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES

class SnippetSerializer(serializers.Serializer):
    #           serializer,  Django Form      json
    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)クラスの第1部は、RESTフレームワークに、どのフィールド(field)がシーケンス化/逆シーケンス化される必要があるかを示す.create()メソッドおよびupdate()メソッドは、コンテンツのあるインスタンスオブジェクトを作成および変更する方法を定義します.この2つのメソッドは、serializer.save()を実行すると呼び出されます.
シーケンサクラスはDjangoのFormクラスに非常に類似しており、複数のフィールドには、requiredmax_lengthおよびdefaultなどの類似の検証識別子も含まれている.
フィールド識別(flag)もできます.シーケンサを制御し、特定の場合、HTMLにレンダリング(rendering)する必要があるなど、どのように表示(displayed)されるかを制御します.上の{'base_template': 'textarea.html'}識別子は、DjangoのFormクラスでwidget=widgets.Textareaを使用することに相当する.これは、特に、可視化されたAPIがどのようにレンダリングされるかを制御する場合に有用である.私たちは後のチュートリアルで、この点を見ることができます.
実際には、ModelSerializerクラスをどのように使用して時間を節約するかを見ることができます.しかし、シーケンサでは、各フィールドの明確な定義を維持します.
Serializer****の使用
さらに理解する前に、新しいSerializerクラスの使用を熟知します.Django shellに入りましょう.
python manage.py shell

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"
') snippet.save() snippet = Snippet(code='print "hello, world"
') snippet.save()

使用可能なコードフラグメントのいくつかのインスタンスがあります.シーケンス化の1つのインスタンスを見てみましょう.
###
            snippet  ,            
     snippet = Snippet(code='print "hello, world"
') snippet.save() ### serializer = SnippetSerializer(snippet) serializer.data # {'id': 2, 'title': u'', 'code': u'print "hello, world"
', 'linenos': False, 'language': u'python', 'style': u'friendly'}

ここで,モデルインスタンスをPythonのオリジナルデータ型(native datatypes)に変換した.シーケンス化のプロセスを完了するには、dataをjsonにレンダリングします.
#       json  
content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\
", "linenos": false, "language": "python", "style": "friendly"}'

逆シーケンス化は似ています.まず、ストリームをPythonデータ型に解析します.
#  json       
from django.utils.six import BytesIO

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

次に、このオリジナルデータ型をオブジェクトインスタンスに変換します.
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() # #

APIの動作形式はこのように似ていることに注意してください.このような繰返し性の類似は,我々のビュー(view)ではシーケンスを用いると,より顕著になる.
モデルインスタンスに加えてquerysetをシーケンス化することもできます.シーケンサのパラメータにmany=Trueを加えるだけです.
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"
'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"
'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'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):
    # ModelSerializer Django ModelForm    
    # Serializer Django Form    
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

シーケンス化プログラムには、シーケンス化されたプロパティを印刷する機能があります.シーケンサオブジェクトのすべてのフィールドを表示します.Django shell(すなわちpython manage.py shell)で試してみましょう.
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クラスは特に不思議なことはしません.シーケンス化器クラスを作成するショートカットにすぎません.
  • フィールドのセットが自動的に宣言されました
  • デフォルトの実装create()およびupdate()メソッド
  • 我々のSerializerを使用して通常のDjangoビューを作成
    新しいSerializerクラスを使用してAPIビューを作成する方法を見てみましょう.これまでREST frameworkの他の特性を使用したことはありませんが、一般的なDjangoビューを作成しただけです.
    HttpResponseのサブクラスを作成することから始めます.このサブクラスは、任意のdataをレンダリングし、jsonに戻ります.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のルートurlは、既存のすべてのコードクリップを表示したり、新しいコードクリップを作成したりするビューになります.
    Python
    @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()
                # serializer.data            
                return JsonResponse(serializer.data, status=201)
            # serializer.errors     
            return JsonResponse(serializer.errors, status=400)
    

    なお、このビューのクライアントにはCSRFトークン(token)がないPOSTデータが必要であるため、ビューにcsrf_exemptとマークする必要がある.あなたは普段そんなことはしませんが、実際には、これよりもREST frameworkのビューの方が合理的な行為をしていますが、今はそうします.
    また、個別のコードクリップに応答し、このクリップを取得、更新、削除するビューも必要です.
    Python
    @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)
    

    最後に、これらのビューを登録する必要があります.作成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),
    ]
    

    また、tutorial/urls.pyファイルのルートurl構成(root urlconf)に登録して、snippets appのURLsを含める必要があります.
    from django.conf.urls import url, include
    
    urlpatterns = [
        url(r'^', include('snippets.urls')),
    ]
    

    注意すべきは、現在、いくつかのエッジイベント(edge cases)があり、対応する処理はありません.乱雑なjsonを送信したり、要求が要求方法を使用したりして、modifyなどのビューに含まれていない場合、500「server error」の応答(response)が表示されます.とにかく、今私たちはしばらくそうします.
    Web APIでの最初のアクセスをテスト
    コードフラグメントをサービスするサンプルサーバを起動できます.
    Django shellを終了...
    quit()
    

    Djangoの開発サーバを起動します.
    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.
    

    別の端末を起動して、サーバをテストすることができます.
    curlまたはhttpieを使用して、APIをテストすることができます.HttpieはPythonで書かれたユーザーフレンドリーなhttpクライアントです.
    pipを使用してhttpieをインストールできます.
    pip install httpie
    

    最後に、すべてのクリップのリストを得ることができます.
    http http://127.0.0.1:8000/snippets/
    HTTP/1.1 200 OK...
    [
      {
        "id": 1,
        "title": "",
        "code": "foo = \"bar\"
    ", "linenos": false, "language": "python", "style": "friendly" }, { "id": 2, "title": "", "code": "print \"hello, world\"
    ", "linenos": false, "language": "python", "style": "friendly" }]

    または、idを参照して特定のコードセグメントを取得できます.
    http http://127.0.0.1:8000/snippets/2/
    
    HTTP/1.1 200 OK
    ...
    {
      "id": 2,
      "title": "",
      "code": "print \"hello, world\"
    ", "linenos": false, "language": "python", "style": "friendly" }

    同様に、WebブラウザでこれらのURLにアクセスすることで、同じjsonを表示できます.
    今どこにいるの?
    これまではまあまあでしたが、シーケンス化されたAPIはDjangoのFormAPIと似ていると感じ、一般的なDjangoビューをいくつか作りました.
    私たちのAPIビューは、まだ特別なことをしていません.jsonに応答したほか、処理できなかったエッジイベントもいくつかあるが、少なくとも使えるWeb APIである.
    このチュートリアルの第2部では、改善を開始する方法について説明します.
    テキストアドレス