Michael Torres
Michael Torres

Reputation: 522

how to do nested routes drf-extensions django using uuid instead of id

I have two Django models - I will change the name of my models here but the idea is the same.

class Photo(models.Model):
  uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
  image = models.ImageField(upload_to='photos')
  created_at = models.DateTimeField(auto_now_add=True)

class Attachment(models.Model):
  uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
  image = models.ImageField(upload_to='attachments')
  created_at = models.DateTimeField(auto_now_add=True)
  photo = models.ForeignKey(Photo, on_delete=models.CASCADE)

I have views:

class PhotoViewSet(viewsets.ModelViewSet):
  serializer_class = PhotoSerialzer
  queryset = Photo.objects.all()

class AttachmentViewSet(viewsets.ModelViewSet):
  serializer_class = AttachmentSerializer
  queryset = Attachment.objects.all()

and in my urls.py file:

router = routers.DefaultRouter()
router.register(r'photo', views.PhotoViewSet, 'photo')
router.register(r'attachments', views.AttachmentViewSet, 'attachment')

class NestedDefaultRouter(NestedRouterMixin, routers.DefaultRouter):
  pass

router = NestedDefaultRouter()

photo_router = router.register('photo', views.PhotoViewSet)
photo_router.register('attachments', views.AttachmentViewSet,
                     basename='photo_attachments', parents_query_lookups=['photo'])

I have built a small app where I can upload pictures via admin and upload attachment pictures to those pictures and saved via aws. I've tried letting Django auto create a primary key but for some reason didn't work all too well, that's even if it did - I can't remember, however, with uuid this was not an issue as you can see I am using it in my model.

My main error now is that even though I want a url like such:

http://127.0.0.1:8000/api/dice/c6e53d17-72ba-4a5f-b72e-26b8b2d25230/attachments/

which I manually inputted into the address bar after checking the uuid of a photo I have in my database (the uuid being c6e53d17-72ba-4a5f-b72e-26b8b2d25230) it just gets all the attachments (even attachments that do not belong to the specified photo using the uuid in the url).

According to this small tutorial here I have pretty much the same setup and instead of id I have a uuid. I am guessing that this is the issue but I'm not sure. I was also thinking that this viewset is a problem:

class AttachmentViewSet(viewsets.ModelViewSet):
  serializer_class = AttachmentSerializer
  queryset = Attachment.objects.all()

being that I am getting back every attachment rather than all attachments attached to a specific photo. I figure I should be using something like filter(photo=photo_uuid) but according to the tutorial I found I don't have to do that, let alone I don't have access to some param like photo_uuid in my viewset so how would I filter in the first place.

To re-iterate, my issue is how do I correctly do nested routes if what I am dealing with uuid rather than id being that this I believe is my problem (unless it's something else). If it's something I have to handle now in my AttachmentViewSet than how to I correctly filter for this. Maybe there is *args or **kwargs but how then would I access this within my viewset if that is the case.

I did find that I can do

def get_queryset(self):
  print(self.kwargs)
  pass

When I print I see what I want and can just return what I want by filtering but is the the actual way of doing it?

Upvotes: 1

Views: 809

Answers (2)

Alireza Dastyar
Alireza Dastyar

Reputation: 88

It has been a long time since this question was asked but since it's still one of top result of google search(for my query at least) I'm writing my take here.

Based on viewsets that you've provided, you are missing NestedViewSetMixin in you'r viewsets (documentation) which can cause this problem.

So to fix it just make sure you inherit the NestedViewSetMixin in you'r viewset like below example:

class PhotoViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
    serializer_class = PhotoSerialzer
    queryset = Photo.objects.all()

Upvotes: 1

Ted Klein Bergman
Ted Klein Bergman

Reputation: 9736

Set the lookup_field to 'uuid' in your viewset.

class AttachmentViewSet(viewsets.ModelViewSet):
    lookup_field = 'uuid'
    serializer_class = AttachmentSerializer
    queryset = Attachment.objects.all()

Upvotes: 3

Related Questions