I have built some Django-Rest-Framework APIs to my application. These APIs do things like return lists of Model Instances and return counts of how many models meet a pre-determined criteria.
Here is what the my ViewSet looks like:
class MyObjectsViewSet(viewsets.ViewSet):
def retrieve(self,request,pk=None):
queryset = ## Do something here to return a list of myObjects
serializer = MyObjectsSerializer(queryset) ## MyObjectsSerializer not shown here.
return Response(serializer.data,status=status.HTTP_200_OK)
And here is what my urls.py looks like for this endpoint:
router = routers.DefaultRouter()
router.register(r'myObjects', views.myObjectsViewSet, base_name="myObjects")
urlpatterns = patterns('',
...
url(r'^api/', include(router.urls)),
...
)
The above code allows me to take a single parameter to the API and use it as the pk argument in MyObjectsViewSet.retrieve(). So when I point my browser to /api/MyObjects/60/, retrieve() is called with pk == 60. Great. Everything is awesome.
But now I need an API that will do something more. I need an API that takes two numeric parameters ("pk" and "otherArg") and calls another viewSet (MyObjectsNewView) with those two arguments. So that when I point my browser to /api/MyObjects/60/59/, MyObjectsNewView.retrieve() will be called with arguments pk == 60 and otherArg == 59.
How can I design my routes in url.py and my Viewsets to make this work?
In other cases, when I was designing non-REST urls, I used regexps and used notation like this to specify extract arguments from a URL string: (?P<MyObjectID>\d+)
.
It would seem like I should be able to do the same type of thing here. However, it automatically takes in the pk argument without me specifying it anywhere in the route, so now I'm confused how to add another argument to this route when the first pk argument sorta appeared magically without any regexp pattern.
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.
Django REST framework (DRF) is a powerful and flexible toolkit for building Web APIs. Its main benefit is that it makes serialization much easier. Django REST framework is based on Django's class-based views, so it's an excellent option if you're familiar with Django.
ModelViewSet. The ModelViewSet class inherits from GenericAPIView and includes implementations for various actions, by mixing in the behavior of the various mixin classes. The actions provided by the ModelViewSet class are .list() , .retrieve() , .create() , .update() , .partial_update() , and .destroy() .
Without using regex drf provides path with type prefix, if you don't have strict validation for "pk" and "otherArg". So,
Step 1: In urlpatters,
path('/api/<int:id>/<otherArg>/', YourViewset.action_name, name="action_name")
Step 2: In Viewset
@action(methods=['get'],detail=True/False)
Step 3: Below @action
def action_name(self, id, otherArg):
Now use id, otherArg/s in function. Make changes and use.
Write a custom detail route and change the signature to pass in the additional kwarg you intend to use. Then, customize the url path.
from rest_framework.decorators import detail_route
from rest_framework import viewsets
class MyObjectsViewSet(viewsets.ViewSet):
@detail_route(methods=['get'], url_path='(?P<oid>\d+)')
def get_with_objectid(self,request,pk=None, oid=None):
queryset = ## Do something here with oid to return a list of myObjects
serializer = MyObjectsSerializer(queryset) ## MyObjectsSerializer not shown here.
return Response(serializer.data,status=status.HTTP_200_OK)
Now your viewset will work with /api/MyObjects/60/59/
where pk=60 and oid=59. If the url_path was instead url_path='/thisthing/(?P(<oid>\d+)'
then the viewset would register /api/MyObjects/60/thisthing/59
.
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