Home > Software engineering >  Implement REST API with Django
Implement REST API with Django

Time:12-31

This is my Django model:

class M(models.Model):
    a = models.IntegerField()
    b = models.IntegerField()

This is the serializer:

class MSerializer(ModelSerializer):
    class Meta:
        model = M
        fields = ['a', 'b']

I would like to be able to implement these REST APIs:

  • 127.0.0.1:8000/m/ (GET list of all elements, POST new element)
  • 127.0.0.1:8000/m/:id/ (GET details of element with id id)
  • 127.0.0.1:8000/n/:a/m/ (GET all elements with a specific a field)

So far this is the view and urls that I implemented:

class MViewSet(ModelViewSet):
    queryset = M.objects.all()
    serializer_class = MSerializer
router = DefaultRouter()
router.register(r'm', MViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

However, in this way the third use case is not working. How can I modify my code to make the third case work? I'd prefer to use as few lines of code as possible (i.e., I would like to use some Django built-in functionalities).

CodePudding user response:

Since it look like you want the 3rd endpoint on another root (possibly another app name n), I'll implement it is a standalone API view, and not as an action on a viewset (although both options are possible)

class FilteredMListView(ListAPIView):
    serializer_class = MSerializer

    def get_queryset(self):
        return M.objects.filter(a=self.kwargs["a"])

Then you register it to the router using:

urlpatterns = [
    path("n/<str:a>/m/", FilteredMListView.as_view())
]

CodePudding user response:

For your 3rd case, I would use a ListAPIView, overriding the get_queryset method to filter by the passed value for a. The idea is that when get_queryset method is invoked, and with as many other filters you'd like to implement, the condition for a is always present. Since the value for a will be in the url, it is mandatory, and you always have in in the view's kwargs. Would look like this:

urls.py

router = DefaultRouter()
router.register(r'm', MViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('<a>/m', AValuesListApiView.as_view()
]

views.py

class AValuesListApiView(generics.ListAPIView):
    queryset = M.objects.all()
    serializer_class = MSerializer

def get_queryset(self):
    return super().get_queryset().filter(score=self.kwargs["score"])
  • Related