Django Rest Framework: как направить uuid к связанному объекту?

Я создаю простое приложение для фотографий-альбомов с помощью Django Rest Framework (DRF). Каждый альбом имеет поле UUID в своей модели. Я хочу создать 'share links', чтобы кто-то со ссылкой вида /albums/[uuid] мог получить доступ к этому альбому.

Я использую ModelViewSet для своих представлений, поэтому я предполагаю, что наиболее лаконичный способ достижения желаемой маршрутизации - это декоратор action, с урлами типа /albums/shared/[uuid], но мне не ясно, как получить uuid в методе shared, декорированном действием. Я даже не могу разобрать URL, потому что DRF будет 404 перед тем, как запустить этот метод shared:

### 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])

Надеюсь, мне не придется добавлять никаких причудливых узоров к urls.py, но если придется, то вот что у меня есть на данный момент:

### myapp/urls.py

router = routers.DefaultRouter()
router.register(r'albums', AlbumViewSet)
...

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

format_suffix_patterns(urlpatterns)

Спасибо!

Здесь вам необходимо внести некоторые изменения в url-pattern и ваш action-decorater:

Первое изменение :

/albums/shared/[uuid] к /albums/[uuid]/shared/ Согласно Docs.

Второе изменение :

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])

Передайте UUID в url и получите его в view... Например. /albums/45/shared/

Ответ, данный @Pradip, идеален, но для справки, вот другое решение, которое у меня работает (кроме части запроса, не проверенной!):

### 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'})),
]

Акции - это здорово, но если вам нужно поддерживать несколько грубых операций или функции ViewSet, такие как пагинация или фильтрация, проще отобразить другой ViewSet через router.register(...)

router.register(r'album', AlbumViewSet)
router.register(r'album/(?P<album_uuid>[\w-]+)/photo', PhotoViewSet)

class PhotoViewSet(ModelViewSet):
    # Filter photos by album uid
    def get_queryset(self):
        qs = super().get_queryset()
        return qs.filter(album_id=self.kwargs["album_uuid"])
Вернуться на верх