14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DjangoAdvent Calendar 2019

Day 21

django-rest-framework 動的にserializerのフィールドを変更する

Last updated at Posted at 2019-12-24

はじめに

django-rest-frameworkserializerを利用してクライアントからのリクエストに応じて動的にフィールドを変更する場合、
公式ガイドにあるクラスを利用し返すことが出来ます。

ビューセットからの呼び出しサンプルです。
ここではフィールドの動的変更のみを行いますが、他のパラメータと組み合わせることで返却するフィールドを柔軟に変更できるようになります。

Dynamic クラスの定義

公式ガイドにあるクラスを利用します。
https://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields

from rest_framework import serializers


class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

モデルの作成

シンプルなコード、名称を持つモデルです。

from uuid import uuid4
from django.db import models


class Customer(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    code = models.CharField(verbose_name='コード', help_text='コード', max_length=10)
    name = models.CharField(verbose_name='名称', help_text='名称', max_length=50)

シリアライザの作成

class CustomerSerializer(DynamicFieldsModelSerializer):
    class Meta:
        model = Customer

        fields = (
            'id',
            'code',
            'name',
        )

ビューセットの作成

get_serializerをオーバーライドし、GETリクエスト時のみクエリ文字列に設定されたフィールド値で
取得する列を動的に変更します。

from rest_framework import viewsets


class CustomerViewSet(viewsets.ModelViewSet):
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer

    def get_serializer(self, *args, **kwargs):
        if self.action == 'list':
            if 'fields[]' in self.request.query_params:
                kwargs['fields'] = self.request.query_params.getlist('fields[]')

        return super().get_serializer(*args, **kwargs)

動作確認

フィールドを指定しない場合

curl -s -X GET "http://localhost:18000/api/customers/" -H "accept: application/json" | jq .
[
  {
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx1",
    "code": "001",
    "name": "test1"
  },
  {
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx2",
    "code": "002",
    "name": "test2"
  }
]

フィールドにcode, nameを指定した場合

curl -s -X GET "http://localhost:18000/api/customers/?fields[]=code&fields[]=name" --globoff -H "accept: application/json" | jq .
[
  {
    "code": "001",
    "name": "test"
  },
  {
    "code": "002",
    "name": "test2"
  }
]
14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?