Django Serializerを使って参照モデルを取得する

#Serializerを簡単にいうと!
モデルオブジェクトをJSONに変換してくれる!

それでは
今回はBookオブジェクトを取得する際に、
ForeignKeyで参照しているAuthorをオブジェクトも含めて取得します!!!!!!!!!!!!

#modelを定義する
サンプルのモデルです！
`Book`モデルは`Author`モデルを参照しています!


```python:models.py
class AbstractModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    is_deleted = models.CharField(max_length=1, default='0')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Author(AbstractModel):
    first_name = models.CharField(max_length=128)
    last_name = models.CharField(max_length=128)

class Book(AbstractModel):
    title = models.CharField(max_length=128)]
    sub_title = models.CharField(max_length=128)]
    price = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    author = models.ForeignKey(Author, on_delete=models.PROTECT, blank=True, null=True)
```
#参照元のモデルも一緒に取得する
## Viewを定義する
genericsのListAPIViewを使って取得APIを作成します!
`author`モデルも取得するのでquerysetには
`select_related`でauthorを指定しておきます。
`all()`なのでも取得することは可能ですが、`select_related.('author')`を
事前に指定しておくことで、発行するSQLを削減できます!!

```python:views.py
from django_filters import rest_framework as filters
from rest_framework import generics

from book.models import Book, Author
from book.serializers import BookSerializer

class ListBook(generics.ListAPIView):
    """Bookを一覧取得するAPI"""
    queryset = Book.objects.select_related('author')
    serializer_class = BookSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_fields = '__all__'
```

# Serializerに参照元Serializerを定義する
`BookSerializer`のフィールドに関連先Serializerを定義することができます!
これで関連先のモデルも取得することができます!!!

ただここで一つ注意なのは参照元のserializerを
定義する時にフィールド名が[lookup](https://docs.djangoproject.com/en/3.1/ref/models/lookups/#module-django.db.models.lookups)に関係しているので間違えないようにしてください!!

```python:serializer.py
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'


class BookSerializer(serializers.ModelSerializer):
    author = AuthorSerializer()
    class Meta:
        model = Book
        fields = '__all__'
```
結果がこちらです!!!!
----
出力結果にはサンプルモデルでは省いたデータも出力されちゃってます!!
飛ばしてください!!

![スクリーンショット 2020-10-22 3.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563930/efcdf7b0-288d-307b-7432-e9131af13304.png)

#参照先のモデルを取得する
先ほどは、Bookモデルと参照元の`Author`モデルも取得しましたが、
逆に、`Author`から`Book`を取得したいと思います!!。
方法は簡単です!

##Viewを定義する
ListAPIViewを使って取得していきたいと思います。
今回は、`select_related`などせずにそのまま`all()`で問題ありません。

```python:views.py
class ListAuthor(generics.ListAPIView):
    """Authorを取得する"""
    queryset = Author.objects.all()
    serializer_class = AuthorBookSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_fields = '__all__'
```

# Serializerの定義
参照先のモデルを取得するため、`book_set`となっています！
これでAPIをリクエストするとAuthorとBookが取得することができます。
この時に、`BookSerializer`に`author = AuthorSerializer()`を残しておくと
`book`取得した時にさらに`author`を再び取得してしまうので注意。


```python:serializers.py
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'


class AuthorBookSerializer(serializers.ModelSerializer):
    book_set = BookSerializer(many=True)
    class Meta:
        model = Author
        fields = '__all__'
```
結果がこちらです!!!!
----
![スクリーンショット 2020-10-22 3.51.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563930/c432f921-e681-aca3-700f-e7481c452c9e.png)


以上になります!