masanorinyo
masanorinyo

Reputation: 1128

JSON API with Django Rest - 'included' attribute

I am creating JSON-API using Django-rest framework. I could structure the returned JSON object in the same way as JSON-API documentation specifies, except for "included" attribute. Is there any way to include multiple serialized objects of related-models?

For example

If I have two model classes

# Snippet Model
from django.db import models
class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    user = models.ForeignKey('auth.User', related_name='snippets')

# Comment Model
from django.db import models
class Comment(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    user = models.ForeignKey('auth.User', related_name='comments')

and I have the serializers for those two models:

from rest_framework import serializers
class SnippetSerializer(serializers.ModelSerializer):
     model = Snippet
     fields = ('id','created', 'title')

from rest_framework import serializers
class CommentSerializer(serializers.ModelSerializer):
     model = Comment
     fields = ('id','created', 'title')

and I have User serializer

# User serializer
from .serializers import SnippetSerializer
from .serializers import CommentSerializer
class UserSerializer(serializers.ModelSerializer):
    included = serializers.SerilizerMethodField()
    class Meta: 
        model = User
        fields = ('id','included')

     def get_included(self, obj):
        included_objs = []
        request = self.context['request']

        # check if requested url has a query parameter "included" 
        query = request.QUERY_PARAMS['included'] if 'included' in  request.QUERY_PARAMS else None
        if query:
             queries = query.split(',')
             if 'included' in queries:
                  snippets = SnippetSerializer(many=True, read_only=True).data
                  comments = CommentSerializer(many=True, read_only=True).data
                  included_objs.append(snippets)
                  included_objs.append(comments)
        return included_objs

and these code didn't give me what I needed.

The objective is that if requested url includes a query "included", then API will return a JSON object with CommentSerialized and SnippetSerialized objects related to user object under 'included' attribute. The result should be something like this.

{
   "id" : 1,
   "included": [
       {'id': 2,'created': "20150729", "title":'snippet' },
       {'id': 2,'created': "20150730", "title":"comment" }, 
       {'id': 3,'created': "20150731", "title":"comment" }, 
   ] 
 }

It would be wonderful if someone can help me out here. Thanks!

Upvotes: 0

Views: 1448

Answers (2)

luislhl
luislhl

Reputation: 1506

The project django-rest-framework-json-api recently implemented support for this behavior.

It's used like this:

class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=200)
    # PostSerializer NOT included directly on the serializer, ResourceRelatedField is 
    # specified as default
    posts = relations.ResourceRelatedField(
        source='post_set', many=True, read_only=True) 

    # specifies serializer to use when passing in the `include` param
    included_serializers = {
        'posts': PostSerializer,
    }

If I understand well, you already implemented part of the JSON-API specification by yourself, so I don't know if it's viable for you to switch things and use their project. But looking on how they implemented what you want may be of some help. See this and this, for example.

Upvotes: 3

kevswanberg
kevswanberg

Reputation: 2119

For this I would write a second serializer:

class IncludedUserSerializer(serializers.ModelSerializer):
      snippets = SnippetSerializer(source = 'snippet_set', many=True)
      comments = CommentSerializer(source = 'comment_set', many=True)

      class Meta:
          model=User
          fields = ('id','snippets', 'comments')

Then in your view override the get_serializer method

 def get_serializer(self):
     if self.query_params.get('included', None):
           return IncludedUserSerializer
     else:
           return UserSerializer

Upvotes: 0

Related Questions