DRF:使用ListModel mixin设置的通用视图上的“不允许获取”

时间:2019-10-13 07:06:12

标签: django django-rest-framework

我在同一URL上有2个视图集,一个用于创建和列出视图,另一个用于检索更新和销毁视图。遵循以下Viewset代码

class UserViewSet(mixins.RetrieveModelMixin,
                  mixins.UpdateModelMixin,
                  mixins.DestroyModelMixin,
                  viewsets.GenericViewSet):
    """
    retrieves user accounts
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (AllowAny,)


class UserCreateViewSet(mixins.CreateModelMixin,
                        mixins.ListModelMixin,
                        viewsets.GenericViewSet):
    """
    Creates user accounts
    """
    queryset = User.objects.all()
    serializer_class = CreateUserSerializer
    permission_classes = (AllowAny,)

    def list(self, request, *args, **kwargs):
        email = self.request.query_params.get('email', None)
        phone_no = self.request.query_params.get('phone_no', None)

        if email is not None:
            queryset = User.objects.filter(email=email)
        elif phone_no is not None:
            queryset = User.objects.filter(phone_no=phone_no)
        else:
            queryset = User.objects.all()
        return super(UserCreateViewSet, self).list(request, *args, **kwargs)

这是我的网址配置:

router = DefaultRouter()
router.register(r'users', UserCreateViewSet)
router.register(r'users', UserViewSet)
router.register(r'advertisement', AdvertisementCreateViewSet)
router.register(r'advertisement', AdvertisementViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api-token-auth/', CustomAuthToken.as_view()),
    path('api-token-auth/verify-otp', VerifyTokenView.as_view()),
    path('api-token-auth/verify-email', VerifyEmailView.as_view()),
    path('api/v1/admin/login', LoginAdminUser.as_view()),
    path('api/v1/user/reset-password/', ResetPasswordView.as_view()),
    url('api/v1/user/(?P<id>.+)/changePassword', ChangePasswordView.as_view())
    path('api/v1/', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    re_path(r'^$', RedirectView.as_view(url=reverse_lazy('api-root'), permanent=False)),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

广告ViewSet在不同的模型上可以做完全相同的事情,并且效果很差。 但是在UserViewSet中却没有。我尝试比较两个视图集的代码,它们完全相同。...

1 个答案:

答案 0 :(得分:0)

我认为您误解了ViewSets的工作方式。单个ViewSet可以包含您希望模型使用的全部逻辑。我认为在您注册路线时会发生冲突,导致ViewSet之一不起作用。

您应该将所有逻辑合并到一个ViewSet中:

class UserViewSet(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    viewsets.GenericViewSet,
):
    queryset = User.objects.all()
    permission_classes = (AllowAny,)

    def get_serializer_class(self):
        """Return the serializer class given the action"""
        action = self.action
        if self.action == 'create' or self.action == 'list':
            return CreateUserSerializer
        else:
            return UserSerializer

    def list(self, request, *args, **kwargs):
        email = self.request.query_params.get('email', None)
        phone_no = self.request.query_params.get('phone_no', None)

        if email is not None:
            queryset = User.objects.filter(email=email)
        elif phone_no is not None:
            queryset = User.objects.filter(phone_no=phone_no)
        else:
            queryset = User.objects.all()
        return super().list(request, *args, **kwargs)

关于我的示例的一些评论:

  • 我覆盖了get_serializer_class,因为我看到您的视图集上有两个不同的序列化器。但是,我很确定您可以使用Serializer字段中的read_only/write_only options做您想要的事情。
  • list视图中,您正在实现一些过滤逻辑。您可以使用django-filter更轻松地执行此操作,而不必重载list方法。