Django REST Framework メモ :: ForeignKeyでつながっている別モデルをくっつけてひとつのJSONとしてWebAPI出力する
はじめに
Django REST Framework でForeignKeyでつながっている別モデルをくっつけてひとつのJSONとしてWebAPI出力する実装方法です。
- 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出力を拡張するのにこのモジュールも使えそうですので共有します。(上記の方法ならこのモジュールを使わずとも出力できますが、モジュールの需要もありそうなので共有します^^ ) django-rest-framework-serializer-extensions.readthedocs.io