Как указать пользовательское поле поиска для действия DRF в наборе представлений?

Я хотел бы указать пользовательское поле поиска в действии (отличное от поля по умолчанию viewset "pk"), т.е.

@action(
        methods=["GET"],
        detail=True,
        url_name="something",
        url_path="something",
        lookup_field="uuid",  # this does not work unfortunately
    )
    def get_something(self, request, uuid=None):
         pass

Но маршрутизатор не генерирует правильные урлы:

router = DefaultRouter()
router.register(r"test", TestViewSet)
router.urls

выдает url:

'^test/(?P<pk>[^/.]+)/something/$'

вместо

'^test/(?P<uuid>[^/.]+)/something/$'

Я не хочу изменять поле поиска для всей модели, и мне не удалось найти способ сделать это для самого действия после отладки через генерацию url маршрутизатора. Я заметил, что наборы представлений модели имеют такой метод:

get_extra_action_url_map(Self)

но я не знаю, как заставить его вызываться для генерации пользовательских урлов и имеет ли он вообще значение. Любая помощь была бы очень кстати, спасибо!

Я думаю, что это создаст большую путаницу для потребителей вашего API, если у вас будет 2 разных идентификатора ресурса на одном и том же ресурсе.

Вы можете назвать это действие query_by_uuid или просто позволить им использовать list_view для фильтрации по uuid, если вы хотите представлять только объект. (чтобы потребители могли использовать /test/?uuid= для получения данных)

Но если вы действительно хотите это сделать, вы можете просто переопределить метод get_object для фильтрации вашего пользовательского действия tho:

def get_object(self):
    if self.action == 'do_something':
        return get_object_or_404(self.get_queryset(), uuid=self.kwargs['pk'])
    return super().get_object()

Согласно их документации вы можете использовать поле поиска regex. В их примере используется CBV вместо представления на основе запроса.

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'uuid'
    lookup_value_regex = '[0-9a-f]{32}'

Это может сработать:

@action(
        methods=["GET"],
        detail=True,
        url_name="something",
        url_path="something",
        lookup_field = 'uuid'
        lookup_value_regex = '[0-9a-f]{32}'
    )
    def get_something(self, request, uuid=None):
         pass
Вернуться на верх