Django REST Framework メモ ::ForeignKeyでつながっている別モデルをくっつけてひとつのJSONとしてWebAPI出力する

###はじめに
Django REST Framework でForeignKeyでつながっている別モデルをくっつけてひとつのJSONとしてWebAPI出力する実装方法です。

転載元ブログ情報

この記事は自分のブログの転載です。
http://k-mawa.hateblo.jp/entry/2018/02/08/000011

###検証した環境
 - Django2
 - Python3.5.2
  
###モデルの設定例  

（例として記事モデル"Article"に対するコメント"Comment"が一覧がくっついてくるような出力を実装するとします）

 - 親モデル（アプリ名articleとします）

```
#article.models.py

class Article(models.Model):
    title = models.CharField(max_length=300, blank=True, null=True)
    cotents_text = models.TextField(blank=True, null=True)
    pubdate = models.DateTimeField(auto_now_add=True)
```
  
 - 子モデル（親モデルをForeignKeyにしている。アプリ名commentとします）

```
#comment.models.py

class Comment(models.Model):
    target_article = models.ForeignKey(Article, on_delete=models.SET_NULL)
    comment = models.TextField(blank=True, null=True)
    pubdate = models.DateTimeField(auto_now_add=True)
```

###Serializerの設定例

 comment.models.pyのCommentモデルのserializerをつくっておきます。

```
#comment.api.serializers.py

class CommentChildSerializer(ModelSerializer):
    class Meta:
        model = Comment
        fields = [
            'id',
            'target_article',
            'comment',
            'pubdate',
        ]
```
__ここからが山場です__  
  
article.models.pyのArticleモデルのserializerをつくっておきます。

```
#article.api.serializers.py


from rest_framework.serializers import SerializerMethodField

from article.models import *
from comment.models import *
from comment.api.serializers import * 
#↑のインポートを忘れずに^^

class ArticleDetailSerializer(ModelSerializer):
    comments = SerializerMethodField() #このフィールドを加えると下記のように出力する値を操作できます。
    class Meta:
        model = Article
        fields = [
            'id',
            'title',
            'cotents_text',
            'pubdate',
            'comments', #モデルには存在しない追加する新フィールド
        ]

    def get_comments(self, obj):
        try:
            comment_abstruct_contents = CommentChildSerializer(Comment.objects.all().filter(target_article = Article.objects.get(id=obj.id)), many=True).data
            #↑ここを"Comment.objects.all().filter(target_article = Article.objects.get(id=obj.id)"
            #とだけにすると、"Item is not JSON serializable"というエラーが出ますので
            #Serializer(出力させたいもの).data　という処理が必要です。
            return comment_abstruct_contents
        except:
            comment_abstruct_contents = None
            return comment_abstruct_contents
```

つぎにviewsを通常のRetrieveAPIViewとかけばOKです。

```
#article.api.views.py

from rest_framework.generics import RetrieveAPIView

from article.models import *
from comment.models import *
from comment.api.serializers import * 


class ArticleDetailAPIView(RetrieveAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleDetailSerializer
    lookup_field = 'pk'

```
最後にurls.pyを書いて動作確認しましょう。

```
from django.urls import path
from .views import ArticleDetailAPIView

urlpatterns = [
   path('detail_articles/<int:pk>/', ArticleDetailAPIView.as_view(), name='detail')
]
```
※引数とpath設定がDjango1系とは異なります

###拡張モジュールも見つけました

DRFのJSON出力を拡張するのにこのモジュールも使えそうですので共有します。（上記の方法ならこのモジュールを使わずとも出力できますが、モジュールの需要もありそうなので共有します^^ ）　

http://django-rest-framework-serializer-extensions.readthedocs.io/en/latest/