ordering of nested serializer output

7,614 views
Skip to first unread message

Colin Nichols

unread,
May 28, 2014, 2:28:36 PM5/28/14
to django-res...@googlegroups.com
Hi all,

I have two models related to each other as follows:

    class Wall(models.Model):
        name = models.CharField(max_length=512)
        ....

    class Brick(models.Model):
        wall = models.ForeignKey(Wall, related_name='bricks')
        dateAdded = models.DateField()

What I want is to create a view that, for a given Wall ID, returns the wall including list of associated Bricks, ordered by date added.

Here's where I'm at... the View:

    class WallViewSet(viewsets.GenericViewSet,
                          mixins.RetrieveModelMixin):
        model = models.Wall
        query_set = models.Wall.objects.all()
        serializer_class = serializers.WallSerializer 

And here are my serializers:

    class WallSerializer(serializers.ModelSerializer):
        bricks = BrickSerializer(many=True, read_only=True)
        class Meta:
            model = Wall

    class BrickSerializer(serializers.ModelSerializer):
        class Meta:
            model = Brick

What is the best way to add sorting list of Bricks by date?

Thanks in advance,
Colin

Xavier Ordoquy

unread,
May 28, 2014, 2:32:46 PM5/28/14
to django-res...@googlegroups.com
Hi Colin,

It looks similar to your current issue.

Regards,
Xavier,
Linovia.

--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Colin Nichols

unread,
May 28, 2014, 3:36:37 PM5/28/14
to django-res...@googlegroups.com
Hi Xavier,

Thanks for the reply.  Indeed it is related but I think the solution to my problem lies elsewhere.  The above link is concerned with ordering the overall result set by a subfield; whereas I would like to specify the ordering of an array of subfields on a single result.  I took a good look thru the code and tried it out, but I'm not sure how I'd adapt it to my particular issue, because I don't know how to get at the queryset for the list of related objects.

Is it possible to specify the ordering of the related objects (bricks in my example above, or tracks in the Album/Track example in documentation)?

Thanks again,
Colin


On Wednesday, May 28, 2014 2:32:46 PM UTC-4, Xavier Ordoquy wrote:
Hi Colin,

It looks similar to your current issue.

Regards,
Xavier,
Linovia.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+unsub...@googlegroups.com.

Xavier Ordoquy

unread,
May 28, 2014, 3:43:07 PM5/28/14
to django-res...@googlegroups.com
Hi Colin,

This should be possible using Django's order_by although I must confess I have never used it on related queries.

Regards,
Xavier,
Linovia.

To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.

Colin Nichols

unread,
May 28, 2014, 4:01:01 PM5/28/14
to django-res...@googlegroups.com
Thanks Xavier!  I agree... but I've already spent too much time on this... popping the chute and using sorted()  :)

Still interested in figuring this out, if anyone has other insights... just spent too much time on it for now.

class WallViewSet(viewsets.ViewSet):
    model = models.Wall
    
    def retrieve(self, request, pk=None):
        queryset = models.Wall.objects.all()
        wall = get_object_or_404(queryset, pk=pk)
        serializer = serializers.WallSerializer(wall)
        data = serializer.data
        data['bricks'] = sorted(data['bricks'],key=lambda brik: brik["date_added"], reverse=True)
        return Response(data)


Thanks,
Colin

Colin Nichols

unread,
Jun 3, 2014, 6:07:08 PM6/3/14
to django-res...@googlegroups.com
OK, got it while working on a related problem.  Here is how I did it:

class WallSerializer(serializers.ModelSerializer):
    class Meta:
        model = Wall

    bricks = serializers.SerializerMethodField('get_bricks')

    def get_bricks(selfself, obj):
        qset = Brick.objects.filter(brick__pk=obj.pk).order_by('-date_added')
        ser = BrickSerializer(qset, many=True, read_only=True)
        return ser.data

Patrick Dizon

unread,
Jul 21, 2014, 11:04:21 AM7/21/14
to django-res...@googlegroups.com
Colin,

This helped me a lot. Thanks for your post.

Patrick

dj Dirk jan

unread,
Sep 9, 2015, 7:53:07 AM9/9/15
to Django REST framework
thanks, this was the solution I needed. pretty hard to find though. took me some time. would posting here help?

I'll just add: django rest nest sort order model

Op woensdag 4 juni 2014 00:07:08 UTC+2 schreef Colin Nichols:

Hari

unread,
Sep 14, 2016, 2:30:25 AM9/14/16
to Django REST framework
Hi Colin,

I a have a similar problem related to ordering. Problem is applying multiple order by in foreign key fields,

Sample code snippet:
 
 class Game(models.Model):
          player = models.ForeignKey(place, null=True, blank=True, verbose_name="place")
          ground = models.ForeignKey(country, null=True, blank=True, verbose_name="place")
          total_score = models.ForeignKey(score, null=True, blank=True, verbose_name="place")

   class Place(Time):
        child = models.CharField(max_length=100,  blank=True, verbose_name="child", db_index=True)
   class country(Time):
        child = models.CharField(max_length=100,  blank=True, verbose_name="country", db_index=True)

    class Time (models.Model):
        time =  models.CharField(max_length=100, null=True, blank=True, verbose_name="time")

Trying to sort based on time:
  Game.objects.filter(...).order_by('-player__time','ground__time')

Winded up with no success.Can you please the problem as you already worked on the similar issue.

Tadej Krevh

unread,
Nov 6, 2016, 5:38:51 PM11/6/16
to Django REST framework
Hi Colin,

there is a very easy method of doing this. Just add ordering Meta information to Brick class:
class Meta:
ordering = ['dateAdded']

Doing it via SerializerMethodField may not be the best solution, as you will be firing additional queries to the database for each Wall.

Kind Regards,
Tadej

Dne sreda, 28. maj 2014 20.28.36 UTC+2 je oseba Colin Nichols napisala:

Colin Nichols

unread,
Nov 6, 2016, 6:22:17 PM11/6/16
to django-res...@googlegroups.com
Tadej, 

For multiple Walls yes there would be too many queries. I think I was only returning one Wall per request so it was ok for me. 

While "ordering" on model meta class does solve the problem, it has the side affect of adding "order by" to all queries for that model class. It can add a lot of overhead for large querysets especially if the column isn't indexed or the index can't be used due to the query. Worst case is a lot of db work, creation of temp tables, etc. This can show up in weird places -- metrics runs, admin pages, etc. and cause issues. 

A solution at the serializer/view/queryset level would be more appropriate. I believe in newer versions of Django you can specify a custom queryset for a prefetch_related. That might be one way to go. Another option would be to add a custom property to the Wall model that just uses sorted() on the related queryset. 

Another benefit of those two approaches is that you can fully leverage prefetch_related(). Having a couple years more Django dev under my belt now, I think this is what I would do. 

-- sent from my phone --
--
You received this message because you are subscribed to a topic in the Google Groups "Django REST framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-rest-framework/L9aXnwS4AQw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-rest-fram...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages