###はじめに
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出力を拡張するのにこのモジュールも使えそうですので共有します。(上記の方法ならこのモジュールを使わずとも出力できますが、モジュールの需要もありそうなので共有します^^ )