DRF: «GET Not Allowed», в общем виде, установленном с помощью Mixin ListModel - PullRequest
0 голосов
/ 13 октября 2019

У меня есть 2 набора просмотра по одному и тому же URL, один для создания и списка, другой для получения обновления и уничтожения. Код 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)

Это моя конфигурация URL:

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 голосов
/ 14 октября 2019

Я думаю, вы не поняли, как 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, потому что я видел, что у вас есть два разных сериализатора в ваших наборах просмотра. Однако я совершенно уверен, что вы можете делать то, что вы хотите, используя read_only / write_only options полей Serializer.
  • В вашем list представлении выреализуют некоторую логику фильтрации. Вы можете сделать это проще с помощью django-filter, не перегружая метод list.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...