Django Rest Framework - 使用 detail_route 和 detail_list

11

我的代码中有一个用户视图集。

我想要的是仅允许读取操作 (/users/42/users/),而ReadOnlyModelViewSet可以很好地实现这一点。

此外,我想要一个/users/register的URL,以便可以通过POST注册新用户。

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @list_route(methods=['post'])
    def register(request):
        serializer = UserSerializer(data=request.DATA)
        if serializer.is_valid():
            user = User.objects.create_user(
                username = serializer.init_data['username'],
                password = serializer.init_data['password'],
            )

            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

几个问题:

  • 这样做是否正确?

  • 如果我把方法放在 list_routedetail_route 装饰器中,该方法是否需要特定的签名(signature)?因为在 detail_route 的例子中,该方法的签名总是相同的:method_name(self, request, pk=None):

谢谢!

2个回答

20

detail_route和detail_list将在DRF 3.0中弃用,而应改为使用@action:

from rest_framework.decorators import action
    @action(methods=['POST'], detail=True)
    def sale(self):
       ...

当这个方法需要代表该端点所表示的模型的单个实例时,请使用detail=True, 当它需要代表该模型的查询集时,请使用False。


2
这是文档: https://www.django-rest-framework.org/community/3.8-announcement/#deprecations - Gregory

13

你的代码几乎正确,只是在注册方法上缺少正确的签名:

def register(self, request):

根据文档,这是正确的签名。此外,测试表明对于路由而言不可能传递额外的参数,并且 @detail_route 始终会传递主键(pk),因此你需要有:

@detail_route
def register(self, request, pk=None):

了解详细路线和

@list_route
def register(self, request):

列出路由的方法。

然而,我建议你利用内置的ViewSetMixins,就像ModelViewSet在内部做的那样

from rest_framework import exceptions, mixins
class UserViewSet(mixins.CreateModelMixin,
               mixins.RetrieveModelMixin,
               mixins.ListModelMixin,
               GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def create(self, request):
        serializer = UserSerializer(data=request.DATA)
            if serializer.is_valid():
                user = User.objects.create_user(
                    username = serializer.init_data['username'],
                    password = serializer.init_data['password'],
                )

                return Response(serializer.data, status=status.HTTP_201_CREATED)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

对于一般用户注册,您也可以查看我目前正在为我的项目使用的 django-registration-restframework

个人在自己的项目中依赖 ModelViewSet,并确保只有经过适当授权的用户才能执行某些操作。要做到这一点,您可以使用模型范围的权限,或结合django guardian对象特定的权限。

特别是在REST API中,您最终会发现希望仅允许特定用户对某些对象执行操作,而无需微调每个请求。此时,对象级别的权限将非常有用。


1
谢谢你的回答,我会看一下。还有一个问题——ModelviewSet允许GET、POST、PATCH、GET和DELETE。当您覆盖更新方法并引发NotAllowed时,这只对POST和PATCH有效吗?还是也适用于DELETE?我的意思是,它是否涵盖了除GET和POST之外的所有方法来创建?只是想确保我只允许所需的方法。 - Ofek Agmon
你说得完全正确。我已经修改了代码,明确使用正确的mixin,而不是通过猴子补丁来修改代码。 - Sebastian Wozny
1
我在这里找不到任何有关详细信息/链接路由的文档片段,因为它已被弃用。谢谢! - Virgílio Santos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接