HTMLとフォーム

REST frameworkは、APIスタイルのレスポンスと通常のHTMLページの両方を返すのに適しています。さらに、シリアライザーはHTMLフォームとして使用でき、テンプレートでレンダリングできます。

HTMLのレンダリング

HTMLレスポンスを返すには、TemplateHTMLRendererまたはStaticHTMLRendererを使用する必要があります。

TemplateHTMLRendererクラスは、レスポンスにコンテキストデータの辞書が含まれていることを期待し、ビューまたはレスポンスで指定する必要があるテンプレートに基づいてHTMLページをレンダリングします。

StaticHTMLRenderクラスは、レスポンスに事前にレンダリングされたHTMLコンテンツの文字列が含まれていることを期待します。

静的なHTMLページは通常、APIレスポンスとは異なる動作をするため、組み込みのジェネリックビューに依存するのではなく、HTMLビューを明示的に記述する必要があるでしょう。

"Profile"インスタンスのリストをHTMLテンプレートでレンダリングして返すビューの例を次に示します。

views.py:

from my_project.example.models import Profile
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView


class ProfileList(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'profile_list.html'

    def get(self, request):
        queryset = Profile.objects.all()
        return Response({'profiles': queryset})

profile_list.html:

<html><body>
<h1>Profiles</h1>
<ul>
    {% for profile in profiles %}
    <li>{{ profile.name }}</li>
    {% endfor %}
</ul>
</body></html>

フォームのレンダリング

シリアライザーは、render_formテンプレートタグを使用してフォームとしてレンダリングし、テンプレートにシリアライザーインスタンスをコンテキストとして含めることができます。

次のビューは、モデルインスタンスの表示と更新のためにテンプレートでシリアライザーを使用する例を示しています。

views.py:

from django.shortcuts import get_object_or_404
from my_project.example.models import Profile
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.views import APIView


class ProfileDetail(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'profile_detail.html'

    def get(self, request, pk):
        profile = get_object_or_404(Profile, pk=pk)
        serializer = ProfileSerializer(profile)
        return Response({'serializer': serializer, 'profile': profile})

    def post(self, request, pk):
        profile = get_object_or_404(Profile, pk=pk)
        serializer = ProfileSerializer(profile, data=request.data)
        if not serializer.is_valid():
            return Response({'serializer': serializer, 'profile': profile})
        serializer.save()
        return redirect('profile-list')

profile_detail.html:

{% load rest_framework %}

<html><body>

<h1>Profile - {{ profile.name }}</h1>

<form action="{% url 'profile-detail' pk=profile.pk %}" method="POST">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save">
</form>

</body></html>

テンプレートパックの使用

render_formタグは、フォームとフォームフィールドのレンダリングに使用するテンプレートディレクトリを指定するオプションのtemplate_pack引数を受け取ります。

REST frameworkには、すべてBootstrap 3に基づいた3つの組み込みテンプレートパックが含まれています。組み込みスタイルはhorizontalverticalinlineです。デフォルトスタイルはhorizontalです。これらのテンプレートパックを使用するには、Bootstrap 3 CSSも含める必要があります。

次のHTMLは、Bootstrap 3 CSSのCDNホストバージョンへのリンクです。

<head>
    …
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>

サードパーティパッケージは、必要なフォームとフィールドテンプレートを含むテンプレートディレクトリをバンドルすることで、代替テンプレートパックを含めることができます。

利用可能な3つのテンプレートパックをそれぞれレンダリングする方法を見てみましょう。これらの例では、「ログイン」フォームを表示するために単一のシリアライザークラスを使用します。

class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField(
        max_length=100,
        style={'placeholder': 'Email', 'autofocus': True}
    )
    password = serializers.CharField(
        max_length=100,
        style={'input_type': 'password', 'placeholder': 'Password'}
    )
    remember_me = serializers.BooleanField()

rest_framework/vertical

標準のBootstrapレイアウトを使用して、対応するコントロール入力の上にフォームラベルを表示します。

これはデフォルトのテンプレートパックです。

{% load rest_framework %}

...

<form action="{% url 'login' %}" method="post" novalidate>
    {% csrf_token %}
    {% render_form serializer template_pack='rest_framework/vertical' %}
    <button type="submit" class="btn btn-default">Sign in</button>
</form>

Vertical form example


rest_framework/horizontal

2/10列の分割を使用して、ラベルとコントロールを並べて表示します。

これは、ブラウズ可能なAPIと管理者レンダラーで使用されるフォームスタイルです。

{% load rest_framework %}

...

<form class="form-horizontal" action="{% url 'login' %}" method="post" novalidate>
    {% csrf_token %}
    {% render_form serializer %}
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">Sign in</button>
        </div>
    </div>
</form>

Horizontal form example


rest_framework/inline

すべてのコントロールをインラインで表示するコンパクトなフォームスタイルです。

{% load rest_framework %}

...

<form class="form-inline" action="{% url 'login' %}" method="post" novalidate>
    {% csrf_token %}
    {% render_form serializer template_pack='rest_framework/inline' %}
    <button type="submit" class="btn btn-default">Sign in</button>
</form>

Inline form example

フィールドスタイル

シリアライザーフィールドは、styleキーワード引数を使用してレンダリングスタイルをカスタマイズできます。この引数は、使用されるテンプレートとレイアウトを制御するオプションの辞書です。

フィールドスタイルをカスタマイズする最も一般的な方法は、base_templateスタイルキーワード引数を使用して、テンプレートパック内のどのテンプレートを使用するかを選択することです。

たとえば、CharFieldをデフォルトのHTML入力ではなくHTMLテキストエリアとしてレンダリングするには、次のようなものを使用します。

details = serializers.CharField(
    max_length=1000,
    style={'base_template': 'textarea.html'}
)

代わりに、含まれているテンプレートパックの一部ではないカスタムテンプレートを使用してフィールドをレンダリングする場合は、templateスタイルオプションを使用してテンプレート名を完全に指定できます。

details = serializers.CharField(
    max_length=1000,
    style={'template': 'my-field-templates/custom-input.html'}
)

フィールドテンプレートは、そのタイプに応じて追加のスタイルプロパティを使用することもできます。たとえば、textarea.htmlテンプレートは、コントロールのサイズに影響を与えるために使用できるrowsプロパティも受け入れます。

details = serializers.CharField(
    max_length=1000,
    style={'base_template': 'textarea.html', 'rows': 10}
)

base_templateオプションとその関連するスタイルオプションの完全なリストを以下に示します。

base_template 有効なフィールドタイプ 追加のスタイルオプション
input.html 任意の文字列、数値、または日付/時刻フィールド input_type、placeholder、hide_label、autofocus
textarea.html CharField rows、placeholder、hide_label
select.html ChoiceFieldまたはリレーショナルフィールドタイプ hide_label
radio.html ChoiceFieldまたはリレーショナルフィールドタイプ inline、hide_label
select_multiple.html MultipleChoiceFieldまたはmany=Trueを持つリレーショナルフィールド hide_label
checkbox_multiple.html MultipleChoiceFieldまたはmany=Trueを持つリレーショナルフィールド inline、hide_label
checkbox.html BooleanField hide_label
fieldset.html ネストされたシリアライザー hide_label
list_fieldset.html ListFieldまたはmany=Trueを持つネストされたシリアライザー hide_label