Django 外部キーのフィールドに設定するキー名を変更する方法

# 何が出来るようになるか
Djangoで一対多のリレーションをJSONで返却するAPIを作成した場合、以下の様なレスポンスが返ってくると思います。この時、外部キーで参照される値のキー名`employee_set`を別名(`employees`)に変更する方法を紹介します。

## レスポンス(キー名変更前)
キー名 `employee_set` を `employees`にしたい。

```bash

[
    {
        "id": "157b2b72-8315-446d-8120-07b408871ef3",
        "name": "ABC",
        "employee_set": [　　　　　　　　　　　　　　　　　　　　　　# キー名を変更したい
            {
                "name": "やまだ"
            },
            {
                "name": "すずき"
            }
        ]
    },
    {
        "id": "5ce3f3fe-7d3c-41c3-b3c0-f11d7d26d59f",
        "name": "XYZ",
        "employee_set": [                                        # キー名を変更したい
            {
                "name": "たなか"
            },
            {
                "name": "たなべ"
            }
        ]
    }
]
```


## 環境
* Python: Python 3.7.1
* Django: 2.2.5
* djangorestframework: 3.10.3


## Model
* 会社(1)：従業員(多)の簡単なモデルを作成します

```models.py
from django.db import models
import uuid


class Company(models.Model):
    """会社テーブル"""

    class Meta:
        db_table = 'company'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(verbose_name="会社名", max_length=30)

    def __str__(self):
        return self.name


class Employee(models.Model):
    """従業員テーブル"""

    class Meta:
        db_table = 'employee'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(verbose_name="氏名", max_length=30)
    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=False)

    def __str__(self):
        return self.name
```

## Serializer
* Djangoでは以下のルールがあります
    1. ForeignKeyを設定したモデルには、関連先のモデルの主キーを扱うために`「ForeignKey のフィールド名」_id`が付与される
        * 今回の場合は、EmployeeモデルからCompanyモデルを参照する
    1. ForeignKeyを設定したモデルには、関連先のモデルを参照するために`「ForeignKey のフィールド名」で参照できる
    1. ForeignKeyが設定されていないモデルでは、逆参照をするために「逆参照先のモデルクラス名(小文字)_set`で逆参照できる
        * 今回の場合は、CompanyモデルからEmployeeモデルを参照する

上記のルールに従って、CompanyのオブジェクトにEmployeeのオブジェクトを入れ子にして返却する場合は、以下の実装になります。その場合、`CompanySerializer`クラスに上記のルール「3」に従って、`employee_set`という変数名を利用して、`fields`の配列に設定する必要があります。

```serializers.py
from rest_framework import serializers
from .models import Company, Employee


class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = ['name']


class CompanySerializer(serializers.ModelSerializer):
    employee_set = EmployeeSerializer(many=True)

    class Meta:
        model = Company
        fields = ['id', 'name', 'employee_set']
```

## View
`ModelViewSet`を継承するだけでサクッとCRUDが作成できるのは本当に助かります；；

```views.py
from rest_framework import viewsets
from .models import Company, Employee
from .serializers import CompanySerializer, EmployeeSerializer


class CompanyViewSet(viewsets.ModelViewSet):
    queryset = Company.objects.all()
    serializer_class = CompanySerializer


class EmployeeViewSet(viewsets.ModelViewSet):
    queryset = Employee.objects.all()
    serializer_class = EmployeeSerializer
```

## 変更方法
2つ方法があります。

* `serialziers.py`を変更する方法
* `models.py`を変更する方法(本記事を記載中、周辺調査の際に見つけました)
    * `serializers.py`も変更が必要

### `serialziers.py`を変更して適用する方法

```serializers.py
from rest_framework import serializers
from .models import Company, Employee


class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = ['name']


class CompanySerializer(serializers.ModelSerializer):
    # employee_set = EmployeeSerializer(many=True)
    employees = EmployeeSerializer(many=True, source='employee_set')
    class Meta:
        model = Company
        fields = ['id', 'name', 'employees']
```

### `models.py`を変更して適用する方法
外部キーを作成する`ForeignKey`に`related_name="キー名"`を指定します。

```models.py
from django.db import models
import uuid


class Company(models.Model):
    """会社テーブル"""

    class Meta:
        db_table = 'company'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(verbose_name="会社名", max_length=30)

    def __str__(self):
        return self.name


class Employee(models.Model):
    """従業員テーブル"""

    class Meta:
        db_table = 'employee'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(verbose_name="氏名", max_length=30)
    company = models.ForeignKey(Company, on_delete=models.CASCADE, null=False, related_name="employees") # related_nameを指定する

    def __str__(self):
        return self.name
```

```serialziers.py
from rest_framework import serializers
from .models import Company, Employee


class EmployeeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = ['name']


class CompanySerializer(serializers.ModelSerializer):
    employees = EmployeeSerializer(many=True)
  
    class Meta:
        model = Company
        fields = ['id', 'name', 'employees']
```

## レスポンス(変更後)
キー名が`employee_set`から`employees`に変更されていることが確認できます。

```bash
[
    {
        "id": "157b2b72-8315-446d-8120-07b408871ef3",
        "name": "ABC",
        "employees": [
            {
                "name": "やまだ"
            },
            {
                "name": "すずき"
            }
        ]
    },
    {
        "id": "5ce3f3fe-7d3c-41c3-b3c0-f11d7d26d59f",
        "name": "XYZ",
        "employees": [
            {
                "name": "たなか"
            },
            {
                "name": "たなべ"
            }
        ]
    }
]
```

# 最後に
DjangoのRestFrameworkを使って返却されるJSONのキー名を変更する方法を紹介しました。Web系のフレームワーク作るならRailsの方が日本語の情報があったり、特に工夫せずにパフォーマンスを上げるならGoなどの選択肢があると思いますが、私の所属している業界では何かと周辺ツールがPythonのライブラリを提供してることが多く、趣味でも活かせそうなのでDjangoを選定しました。少しでも皆さんのお役に立てると幸いです。