How to access path url parameter in DRF serializer?

Viewed 3126

Short question:

What's the appropriate way to access a url path parameter (not a url query parameter) in a Django DRF serializer?

Context:

A have a Django DRF api, where I have a url similar to :

/api/blogposts/:blogid/comments

that is handled by a generic view:

class MyCommentsView(generics.ListCreateAPIView):
       queryset = Comment.objects.all()
       serializer_class = CommentSerializer

(blog and comment are just example resources; i am working with different ones)

This view allows via a POST call to create new comments. For legacy reasons, the request will contain the blog_id also as a request body parameter.

In my Serializer I want to check if the :blogid in the url is identical to the blog_id in the body. Currently I do the following, but the path splitting and element selecting feels very fragile (e.g. if I restructure my url in urls.py I need to adjust my custom parsing) . So, is there a better way?

class CommentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = [..., 'blog_id', ... ]

    ...

    def validate_blog_id(self, value):
        # Better way for next line?
        blogid_in_url = int(self.context['request'].path.split('/')[-2]) 
        if blogid_in_url != value:
             ...

Note: my question is about a url path parameter, not a url query parameter (like blogid in api/blogposts?blogid=55). I know a url query parameter can be accessed via self.context['request'].query_params.

1 Answers

I can't say it is a good way but suggest alternatively:

You can access your url parameters in your serializer like this:

self.context.get('request').parser_context.get('kwargs').get(
        'blog_id') # your url parameter name here

Another way, you can override create method of ListCreateAPIView;

def create(self, request, *args, **kwargs):
    blog_id = kwargs.get('blog_id') # your url parameter name here
    serializer = self.get_serializer(data=request.data, 
                                     context={'blog_id': blog_id})
    serializer.is_valid(raise_exception=True)
    self.perform_create(serializer)
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED,
                    headers=headers)
Related