I wish to implement my new API with a nested resource.
Example: /api/users/:user_id/posts/
Will evaluate to all of the posts for a specific user. I haven't seen an working example for this use case, maybe this isn't the right way for implementing rest API?
DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.
Nesting resources provide REST API consumers an easy and efficient way to manage data by allowing the consumer to send and receive only the required object. The nested resource must be a business object, that is, it must still represent a complete business object.
basename - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the queryset attribute of the viewset, if it has one. Note that if the viewset does not include a queryset attribute then you must set basename when registering the viewset.
As commented by Danilo, the @link
decorator got removed in favor of @list_route
and @detail_route
decorators.
@detail_route
& @list_route
got deprecated in favor of @action
.Here's the alternate solutions:
@detail_route()
def posts(self, request, pk=None):
owner = self.get_object()
posts = Post.objects.filter(owner=owner)
context = {
'request': request
}
post_serializer = PostSerializer(posts, many=True, context=context)
return Response(post_serializer.data)
Try drf-nested-routers
. Haven't tried this out yet, but looks promising, many are already using it. Looks like an advanced version of what we are already trying to achieve.
Hope this helps.
To map /api/users/:user_id/posts/
you can decorate a posts
method inside your ViewSet
with @link()
from rest_framework.decorators import link
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
model = User
serializer_class = UserSerializer
# Your regular ModelViewSet things here
# Add a decorated method like this
@link()
def posts(self, request, pk):
# pk is the user_id in your example
posts = Post.objects.filter(owner=pk)
# Or, you can also do a related objects query, something like:
# user = self.get_object(pk)
# posts = user.post_set.all()
# Then just serialize and return it!
serializer = PostSerializer(posts)
return Response(serializer.data)
As commented by Danilo Cabello earlier you would use @detail_route
or @list_route
instead of @link()
. Please read the documentation for "Routers", section "Extra link and actions" and "ViewSets", section "Marking extra actions for routing" for detailed explanations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With