Возможно иметь метод в APIView, вызываемый из url-адреса

в Django Rest Framework можно иметь пользовательский метод в APIView класс можно назвать как .get() или .post() будет называться.

Я знаю, что это возможно с маршрутизаторами с использованием @action() или @link() декораторы, я пытаюсь выяснить, можете ли вы сделать что-то похожее на APIView но имейте это, чтобы я мог установить метод на любой url, который я хочу.

Я пытался украсить класс с @action() и @api_view() но кажется, ничего работал.

Я не совсем уверен, что я должен поместить в URL-адрес конечной точки, чтобы фактически вызвать метод в классе. Буду ли я использовать CartAPIView.clear.as_view(), CartAPIView.clear или CartAPIView.clear(). Я пробовал разные комбинации вызовов CartAPIView но ничего не работает.

вот пример того, что я пытаюсь сделать:

# views.py
class CartAPIView(APIView):
    @api_view(['POST'])
    def clear(self, request):
        """Clear the users cart."""
        queryset = Cart.objects.get(user=request.user)

        queryset.clear_cart()

        serializer = CartSerializer(queryset)

        return Response(serializer.data, status=status.HTTP_200_OK)

# urls.py
urlpatterns = patterns('app.views',
    ....
    url(r'^cart/clear/$', CartAPIView.clear.as_view(), name='clear_cart_api'),
    ....
)

любая помощь будет оценили.

3 ответов


вы, кажется, упускаете из виду, как работает поток представления на основе класса.

  • как класс на основе класса (очевидно), и Django ожидает несвязанная функция (не прикрепленная к классу или экземпляру) в виде представления, as_view обрабатывает это, создавая несвязанную функцию, и в этой функции создает экземпляр на основе класса вид.
  • as_view вызывает self.dispatch(request, *args, **kwargs), где self - это только что созданный экземпляр объекта.
  • dispatch звонки self.get(request, *args, **kwargs) или self.post(request, *args, **kwargs) в зависимости от метода запроса (или put, patch или delete если это разрешено и используется).

там нет места для пользовательской функции, как ваш clear функция, если вы не переопределите один из этих методов для вызова self.clear(request). Эквивалент @api_view(['POST']) было бы переопределить post(request, *args, **kwargs) способ:

# views.py
class CartAPIView(APIView):
    def post(self, request, *args, **kwargs):
        # Why would you call this 'queryset'? It's a single object.
        cart = Cart.objects.get(user=request.user)
        cart.clear_cart()

        serializer = CartSerializer(cart)
        return Response(serializer.data, status=status.HTTP_200_OK)

# urls.py
urlpatterns = patterns('app.views',
    url(r'^cart/clear/$', CartAPIView.as_view(), name='clear_cart_api'),
)

Кажется, что вы ищете Представления На Основе Функций, где вы можете украсить функция с @api_view()

from rest_framework.decorators import api_view

@api_view(['POST'])
def clear(request):
    """Clear the users cart."""
    queryset = Cart.objects.get(user=request.user)

    queryset.clear_cart()

    serializer = CartSerializer(queryset)

    return Response(serializer.data, status=status.HTTP_200_OK)


# urls.py
urlpatterns = patterns('app.views',
    ....
    url(r'^cart/clear/$', 'clear', name='clear_cart_api'),
    ....
)

оба ответа, опубликованные здесь @knbk и @almalki, являются действительными подходами к тому, что я спрашивал. Однако они не показывают, что я на самом деле сделал через несколько часов или около того.

Я закончил с помощью ViewSets, которые позволили мне связать GET, POST, etc запрашивает определенную функцию в классе ViewSet. Обычно вы используете маршрутизаторы для автоматической привязки всех соответствующих функций, но я хотел немного больше гибкости с тем, как они были связаны, так что я просто выписал их сам.

# views.py
class CartViewSet(ViewSet):
    def clear(self, request):
        """Clear the users cart."""
        queryset = Cart.objects.get(user=request.user)

        queryset.clear_cart()

        serializer = CartSerializer(queryset)

        return Response(serializer.data, status=status.HTTP_200_OK)

clear_cart_viewset = CartViewSet.as_view({
    'post': 'clear'
})

# urls.py
urlpatterns = patterns('app.views',
    ....
    url(r'^cart/clear/$', 'clear_cart_viewset', name='clear_cart_api'),
    ....
)