Monday, 21 June 2021

ViewSet and additional retrieve URL

I have a django model Donation that I expose as a ViewSet. Now I want to add an additional URL to a second model Shop where a related instance of Donation can be retrieved via the parameter order_id and custom actions can be executed.

# models.py
class Donation(models.Model):
  id = models.AutoField(primary_key=True)
  order_id = models.StringField(help_text='Only unique in combination with field `origin`')
  origin = models.ForeignKey('Shop', on_delete=models.PROTECT)

class Shop(models.Model):
  id = models.AutoField(primary_key=True)
  

# views.py
class DonationViewSet(mixins.CreateModelMixin,
                     mixins.RetrieveModelMixin,
                     mixins.ListModelMixin,
                     viewsets.GenericViewSet):

  def retrieve(self, request, *args, **kwargs):  
    if kwargs['pk'].isdigit():
      return super(DonationViewSet, self).retrieve(request, *args, **kwargs)
    else:
      shop_id = self.request.query_params.get('shop_id', None)
      order_id = self.request.query_params.get('order_id', None)
      
      if shop_id is not None and order_id is not None:
        instance = Donations.objects.filter(origin=shop_id, order_id=order_id).first()
        if instance is None:
          return Response(status=status.HTTP_404_NOT_FOUND)
        
        return Response(self.get_serializer(instance).data)

      return Response(status=status.HTTP_404_NOT_FOUND)

  @action(methods=['post'], detail=True)
  def custom_action(self, request, *args, **kwargs):
      pass

class ShopViewSet(viewsets.ModelViewSet):
  pass

# urls.py
router = routers.DefaultRouter()

router.register(r'donations', DonationViewSet)
router.register(r'shops', ShopViewSet)
router.register(r'shops/(?P<shop_id>[0-9]+)/donations/(?P<order_id>[0-9]+)', DonationViewSet)

My goal is to have http://localhost:8000/donations point at the entire DonationViewSet. Also I would like to lookup an individual donation, by its combination of shop_id and order_id like follows http://localhost:8000/shops/123/donations/1337/ and also executing the custom action like follows http://localhost:8000/shops/123/donations/1337/custom_action/. The problem I have is that the second url returns an entire queryset, not just a single instance of the model.



from ViewSet and additional retrieve URL

No comments:

Post a Comment