I am building a simple photos-albums app with Django Rest Framework (DRF). Each album has a UUID field in its model. I want to create 'share links' so that someone with a link of the form /albums/[uuid] will be able to access that album.
I am using ModelViewSet for my views, so I assume that the most succinct way to achieve this desired routing is via the action decorator, with urls like /albums/shared/[uuid], but it's not clear to me how to obtain the uuid in the action-decorated shared method. I can't even parse the URL because DRF will 404 before firing this shared method:
### views/album.py
class AlbumViewSet(viewsets.ModelViewSet):
queryset = Album.objects.all()
serializer_class = AlbumSerializer
@action(detail=False, methods=['get'])
def shared(self, request):
# How do you get the uuid from the supplied URL?
uuid = ???
obj = self.get_queryset().objects.get(uuid=uuid)
return Response([obj])
Hopefully I won't have to add any fancy patterns to urls.py, but if I do then here is what I have so far:
### myapp/urls.py
router = routers.DefaultRouter()
router.register(r'albums', AlbumViewSet)
...
urlpatterns = [
# ...
path('', include(router.urls)),
]
format_suffix_patterns(urlpatterns)
Thanks!
CodePudding user response:
Here you need to some changes in url-pattern and your action-decorater:
First Change :
/albums/shared/[uuid] to /albums/[uuid]/shared/ According to Docs.
Second Change :
class AlbumViewSet(viewsets.ModelViewSet):
queryset = Album.objects.all()
serializer_class = AlbumSerializer
⬇⬇⬇⬇
@action(detail=True, methods=['get'])
def shared(self,request,pk=None): ⬅⬅⬅⬅
uuid = pk
obj = self.get_queryset().objects.get(uuid=uuid)
return Response([obj])
Pass UUID in url and fetch it in view... For ex. /albums/45/shared/
CodePudding user response:
The answer given by @Pradip is perfect but, for my own reference, here is a different solution I got working (except query part not tested!):
### myapp/views/album.py
class AlbumViewSet(viewsets.ModelViewSet):
...
@action(detail=False, methods=['get'],)
def shared(self, request, *args, **kwargs):
uuid = kwargs.get('uuid', None)
if uuid:
try:
obj = self.get_queryset().get(name=uuid)
return Response([obj])
except Album.DoesNotExist:
obj = None
raise exceptions.NotFound(f'Album with UUID {uuid} not found')
else:
raise exceptions.ParseError('UUID not parseable')
### myproject/urls.py
urlpatterns = [
...
path('albums/<str:uuid>/shared/', AlbumViewSet.as_view({'get': 'shared'})),
]
