Different Serializers for Get/Post

2,096 views
Skip to first unread message

Andre Giannico

unread,
Jan 31, 2013, 4:39:21 PM1/31/13
to django-res...@googlegroups.com
I'm using the generics.ListCreateAPIView to expose a list (GET) and create (POST) service for a resource.

Due to the nature of the web app that will be consuming the resource, I'd like to represent one of the resource relationships as a Nested Object during GET - however, I'd like to specify the relationship as an ID (or hyperlinked ID) while POSTing a new resource.

It seems the ListCreateApiView only allows you to specify a single serializer_class to use for both the GET/POST requests. Is there any way to achieve what I'm trying to accomplish, while still using the simple ListCreateApiView? If not, what's the best alternative (just using ApiView)?

Thanks,
Andre Giannico

Steven Kane

unread,
Feb 1, 2013, 1:51:37 AM2/1/13
to django-res...@googlegroups.com
Andre,

The easiest approach I can think of for this problem is to over-write the "list" and "post" operations inside your view definition.  You will be best served in doing this by largely copying the definitions of these methods as they are found in mixins.py.

Instead of using the .get_serializer() method simply write code that will use your particular serializer class to serialize the data.  For example:

replace
serializer = self.get_serializer(data=request.DATA, files=request.FILES) 

with
serializer = ObjectPostSerializer(data=request.DATA, files=request.FILES)
where ObjectPostSerializer is the serializer you would like to use with your post method.

You could follow the same pattern with the "create" method, or alternatively, you could leave it as-is and simply let it use the serializer you declare on the view.  Whatever you feel is more explicit/clear.  

If, however, you are merely wanting to define different expectations for serialization vs de-serialization then I recommend just writing a complete serializer that specifies exactly what will happen when models are serialized and what will happen when data is recieved to be de-serialized.  

If that is not clear or just way off let me know.

Steve Kane

Tom Christie

unread,
Feb 1, 2013, 4:18:10 AM2/1/13
to django-res...@googlegroups.com
Steven's approach is pretty sensible - if the existing generic views don't quite fit in with what you need, then you can't go far wrong with just explicitly overriding the actions on the views.

If you did want to take a more generic route, eg. if you're using this on multiple views. you could consider overriding the `.get_serializer_class` method, so that you could define both a `.serializer_class` and a `.nested_serializer_class`, and determine which to use based on the method of the incoming request.

--
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/groups/opt_out.
 
 

Steven Kane

unread,
Feb 1, 2013, 12:43:52 PM2/1/13
to django-res...@googlegroups.com
I think Tom's plan to override get_serializer_class is clearly the more elegant solution regardless.  In my opinion, this is the correct API hook to edit to achieve your goals.

Steve

Andre Giannico

unread,
Feb 1, 2013, 4:21:07 PM2/1/13
to django-res...@googlegroups.com
Thanks - these were great suggestions! I'm still pretty new to Python (yet, I was able to build a pretty solid RESTful API with DRF - a testament to the framework!).

Could either of you give me a quick code review to see if this looks reasonable (a List view for serializing tasks - if I want the nested version I'm passing a query parameter of "nested")?

class TaskList(generics.ListCreateAPIView):
    model = Task
    serializer_class = TaskSerializer
    nested_serializer_class = NestedTaskSerializer

    def get_serializer_class(self):

        if "nested" in self.request.QUERY_PARAMS and hasattr(self, 'nested_serializer_class'):
            return self.nested_serializer_class
        else:
            return super(generics.ListCreateAPIView, self).get_serializer_class()

Steven Kane

unread,
Feb 1, 2013, 4:46:51 PM2/1/13
to django-res...@googlegroups.com
I qualify this by saying that I am also very new to development in general and python specifically so take my comments w/ a grain of salt.  I have written a small library to do query parsing from request.META.get('query_string') because I have found it a more stable source of query parameters than QUERY_PARAMS.  As such, I would recommend putting in some code to change your conditional to a retrieval and parsing of request.META.get('query_string') before checking if your query is there.

You can see an example of code that does a similar thing in my project at:

The list method in jsonrootviews.py should be fairly similar to the code I am describing.  

Furthermore, unless you are forced to use this methodology by a fixed front-end API scheme, I would encourage you to simply handle this w/ different URL routes.  It will be cleaner and probably will feel more obvious when being used.  It's easier to send HTTP requests to a different URL depending on desired format than to parse into different formats based on input type and query parameters.

All that being said, your code does do exactly what you indicated you want it to do and it's readable and pretty idiomatic from a django point of view.  

Steve


--

Andre Giannico

unread,
Feb 1, 2013, 11:42:52 PM2/1/13
to django-res...@googlegroups.com
Thanks Steve, I appreciate the feedback - I checked out your code, thanks for the example. Out of curiosity, what type of issues have you come across with QUERY_PARAMS?

Also, small world - I saw someone mention your Django/Ember project on Twitter last night. I'll definitely keep an eye on your Git project - I've been looking forward to jumping into Ember.js (been really enjoying AngularJS and want to see how it compares).

Thanks again for the help!
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages