16

This question is being asked to expand and fill in the holes from this one: Return results from multiple models with Django REST Framework

my goal is to return a json object that I will use to dynamically populate the options in various select statements in my html code.

so I want to grab a attribute from model a, another from model b etc

then I want all the values from attribute a and b and c etc

to be in a value as a JSON array to a key so

json = {
    modelA: {'atter1, atter2, atter3}
    modelB: {'atter1, atter2, atter3}
    model..:{you get the point}
}

this part from the post referenced above makes sense:

class TimelineViewSet(viewsets.ModelViewSet):
    """
    API endpoint that lists all tweet/article objects in rev-chrono.
    """
    queryset = itertools.chain(Tweet.objects.all(), Article.objects.all())
    serializer_class = TimelineSerializer

what doesn't is this:

class TimelineSerializer(serializers.Serializer):
    pk = serializers.Field()
    title = serializers.CharField()
    author = serializers.RelatedField()
    pub_date = serializers.DateTimeField()

how do I set the the seperate model attributes to the correct json key?

I assume its something similar to a serializer relation but these values aren't related to eachother via onetoone, onetomany, or many to many. I just want to grab all this info at once instead of creating an api for each value.

I am a lost little girl and I am asking you to help me find my way home.

2 Answers 2

47

You'll find things easier in Django REST Framework if you design your response format rationally.

It seems a bit vague at the moment, but I would suggest something like:

{
    "tweets": [
        {"tweet_attr_A": value_1, ...},  // first tweet
        {"tweet_attr_A": value_2, ...},  // second tweet
        //etc
    ],
    "articles": [
        {"id": 1, ...},  // first article
        {"id": 2, ...},  // second article
        //etc
    ]
}

We can express this with three serializers, like:

class TweetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tweet

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article

class TimelineSerializer(serializers.Serializer):
    tweets = TweetSerializer(many=True)
    articles = ArticleSerializer(many=True)

http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects

Then, because we're using more than one model, it's easiest just to define your own custom viewset rather than trying to shoe-horn this into DRF's magic ModelViewSet type.
http://www.django-rest-framework.org/api-guide/viewsets/#example

First we need an object type to pass into our TimelineSerializer. It should have two attributes: tweets and articles

from collections import namedtuple

Timeline = namedtuple('Timeline', ('tweets', 'articles'))

Then we'll define the custom viewset to fetch the tweets and articles, instantiate a Timeline object and return the TimelineSerializer data:

class TimelineViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing the Tweets and Articles in your Timeline.
    """
    def list(self, request):
        timeline = Timeline(
            tweets=Tweet.objects.all(),
            articles=Article.objects.all(),
        )
        serializer = TimelineSerializer(timeline)
        return Response(serializer.data)
Sign up to request clarification or add additional context in comments.

8 Comments

hey man this answer is really good and really complete. I wanted to thank you on a deeper level than I did initally. Thank you very much!!!!!
@amazingCarrotSoup you're welcome! I had been thinking about adding a follow-up: it occurred to me maybe in context of a 'timeline' you want all the content types returned together in a single list, ordered by date. But this becomes a data-model problem: to order them when fetching from the db you'd need to get them in a single query. And to serialize them in DRF they all need to be the same type of object. So this implies instead of separate Tweet and Article models you'd need a single TimelineItem model that could represent both types of content.
@Anetropic I get what your sayng and this isn't the execution I was going for but I completely understand why I would have to serialize as the same type. Again I appreciate you!
@Anentropic do you have an example of it in timelineitem. Im trying to implement it but it's not working. stackoverflow.com/questions/47499261/…
@Anentropic great detail. note i received an error message related to instantiating the serializer without the request context. serializer=TimelineSerializer(timeline, context={"request": request}) works.
|
2

I had a same situation to serialize multiple models to fetch filtered output from each serialize model to use from one single api. I came across this module to achieve this result.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.