Django-rest-framework permisos para crear en conjunto de vistas

Estoy tratando de crear una API REST y estoy atascado en el registro del usuario: básicamente necesito tener el token de acceso antes de registrarme.

Esta es la vista:

class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ queryset = User.objects.all() serializer_class = UserSerializer def metadata(self, request): """ Don't include the view description in OPTIONS responses. """ data = super(UserViewSet, self).metadata(request) return data def create(self, request): serializer = self.get_serializer(data=request.DATA, files=request.FILES) if serializer.is_valid(): self.pre_save(serializer.object) self.object = serializer.save(force_insert=True) self.post_save(self.object, created=True) self.object.set_password(self.object.password) self.object.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

Esta es la solución:

 @api_view(['POST']) @permission_classes((AllowAny,)) @csrf_exempt def create_auth(request, format=None): data = JSONParser().parse(request) serialized = UserSerializer(data=data) if serialized.is_valid(): user = User.objects.create_user( serialized.init_data['email'], serialized.init_data['username'], serialized.init_data['password'], ) user.groups = serialized.init_data['groups'] user.save() serialized_user = UserSerializer(user) return Response(serialized_user.data, status=status.HTTP_201_CREATED, headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8000/"}) else: return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST, headers={"Access-Control-Allow-Origin": "http://127.0.0.1:8000/"}) 

Mi pregunta es: ¿Cómo puedo especificar en el UserViewSet que para la creación no necesito credenciales? ¿O especificar un método de autenticación personalizado? No quiero cambiar las clases de autenticación / permiso para todo el conjunto de vistas.

Gracias adi

EDITAR para aclarar: los usuarios no registrados deben tener permitido POST datos de registro y no se les debe permitir nada más. Los usuarios autenticados pueden obtener la lista de usuarios y actualizar su propio perfil … este es el comportamiento predeterminado. Por eso AllowAny no es una opción. En mi opinión, el lugar adecuado para esto es la función de creación , pero no consigo lo que se supone que debo anular.

Personaliza el método get_queryset:

 def get_queryset(self): if self.request.user.is_superuser: return User.objects.all() else: return User.objects.filter(id=self.request.user.id) 

De esta manera, un usuario autenticado solo puede recuperar, modificar o eliminar su propio objeto.

Especifique el permission_classes = (AllowAny,) para que un usuario autenticado pueda crear uno nuevo.

EDITAR : explicación adicional a partir de los comentarios.

Personalizar el método get_queryset de esta manera significa lo siguiente:

  1. Sí, los usuarios no autenticados pueden enviar la solicitud GET para recuperar la lista de usuarios, pero estará vacía porque la respuesta User.objects.filter (id = self.request.user.id) garantiza que solo se devuelva información sobre el usuario autenticado .

  2. Lo mismo se aplica a otros métodos, si un usuario autenticado intenta BORRAR otro objeto de usuario, se mostrará un detalle: No encontrado (porque el usuario al que intenta acceder no se encuentra en el conjunto de consultas).

  3. Los usuarios autenticados pueden hacer lo que quieran con sus objetos de usuario.

Podría utilizar la capacidad de Django REST Framework para definir permisos personalizados. Puede especificar un has_permission y has_object_permission dentro de una clase personalizada. Esto le dará el comportamiento esperado de lanzar 403s a los usuarios de anon para todo excepto para publicar en el punto final de creación. Podría parecer algo como:

 class IsAnonCreate(permissions.BasePermission): def has_permission(self, request, view): if request.method == "POST" and not request.user.is_authenticated(): return True elif not request.user.is_authenticated() and request.method != "POST": return False elif request.method in permissions.SAFE_METHODS: return True return False def has_object_permission(self, request, view, obj): if not request.user.is_authenticated(): return False if request.method in permissions.SAFE_METHODS: return True return obj.username == request.user.username 

Si lo desea, puede agregar un manejo personalizado para los usuarios autenticados.

Entonces todo lo que necesita hacer es agregar la clase de permiso a su ModelViewSet :

 class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ queryset = User.objects.all() serializer_class = UserSerializer permission_classes = (IsAnonCreate, ) 

Esto se basa en la respuesta de @argaen y funcionó para mí:

 class UserViewSet(viewsets.ModelViewSet): serializer_class = UserSerializer permission_classes = (AllowAny,) authentication_classes = (NoAuthentication,) filter_backends = (filters.DjangoFilterBackend,) filter_fields = ('id', 'email', 'name') def get_queryset(self): user = TokenAuthentication().authenticate(self.request) if user is not None: user = user[0] if user.is_superuser: return get_user_model().objects.all() else: return get_user_model().objects.filter(id=user.id) return get_user_model().objects.none()