usuarios - tipos de usuario django
¿Cómo registrar usuarios en el marco Django REST? (8)
Estoy codificando una API REST con el marco Django REST . La API será el back-end de una aplicación móvil social. Después de seguir el tutorial, puedo serializar todos mis modelos y puedo crear nuevos recursos y actualizarlos.
Estoy usando AuthToken para la autenticación.
Mi pregunta es:
Una vez que tenga el recurso /users
, quiero que el usuario de la aplicación pueda registrarse. Entonces, ¿es mejor tener un recurso separado como /register
o permitir que usuarios anónimos envíen a /users
un nuevo recurso?
Además, alguna orientación sobre permisos sería genial.
@cpury arriba sugirió utilizar la opción write_only_fields
. Sin embargo, esto no funcionó para mí en DRF 3.3.3
En DRF 3.0, la opción write_only_fields
en ModelSerializer se ha movido a PendingDeprecation y en DRF 3.2 se ha reemplazado por un extra_kwargs más genérico:
extra_kwargs = {''password'': {''write_only'': True}}
Actualicé la respuesta de Cahlan para admitir modelos de usuario personalizados de Django 1.5 y devuelvo la identificación del usuario en la respuesta.
from django.contrib.auth import get_user_model
from rest_framework import status, serializers
from rest_framework.decorators import api_view
from rest_framework.response import Response
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
@api_view([''POST''])
def register(request):
VALID_USER_FIELDS = [f.name for f in get_user_model()._meta.fields]
DEFAULTS = {
# you can define any defaults that you would like for the user, here
}
serialized = UserSerializer(data=request.DATA)
if serialized.is_valid():
user_data = {field: data for (field, data) in request.DATA.items() if field in VALID_USER_FIELDS}
user_data.update(DEFAULTS)
user = get_user_model().objects.create_user(
**user_data
)
return Response(UserSerializer(instance=user).data, status=status.HTTP_201_CREATED)
else:
return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
Django REST Framework 3 allow anular el método de create
en serializadores:
from rest_framework import serializers
from django.contrib.auth import get_user_model # If used custom user model
UserModel = get_user_model()
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = UserModel.objects.create(
username=validated_data[''username'']
)
user.set_password(validated_data[''password''])
user.save()
return user
class Meta:
model = UserModel
También api.py :
from rest_framework import permissions
from rest_framework.generics import CreateAPIView
from django.contrib.auth import get_user_model # If used custom user model
from .serializers import UserSerializer
class CreateUserView(CreateAPIView):
model = get_user_model()
permission_classes = [
permissions.AllowAny # Or anon users can''t register
]
serializer_class = UserSerializer
La solución más simple, trabajando en DRF 3.x:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (''id'', ''username'', ''password'', ''email'', ''first_name'', ''last_name'')
write_only_fields = (''password'',)
read_only_fields = (''id'',)
def create(self, validated_data):
user = User.objects.create(
username=validated_data[''username''],
email=validated_data[''email''],
first_name=validated_data[''first_name''],
last_name=validated_data[''last_name'']
)
user.set_password(validated_data[''password''])
user.save()
return user
No necesita otros cambios, solo asegúrese de que los usuarios no autenticados tengan permiso para crear un nuevo objeto de usuario.
write_only_fields
se asegurará de que las contraseñas (en realidad: su hash que almacenamos) no se muestren, mientras que el método de create
sobrescrito garantiza que la contraseña no se almacene en texto claro, sino como un hash.
Normalmente trato la vista de usuario como cualquier otro punto final de API que requiera autorización, excepto que simplemente anulo el conjunto de permisos de la clase de vista con el mío para POST (también conocido como create). Normalmente utilizo este patrón:
from django.contrib.auth import get_user_model
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
class UserViewSet(viewsets.ModelViewSet):
queryset = get_user_model().objects
serializer_class = UserSerializer
def get_permissions(self):
if self.request.method == ''POST'':
self.permission_classes = (AllowAny,)
return super(UserViewSet, self).get_permissions()
Para una buena medida, aquí está el serializador que normalmente uso con él:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = (
''id'',
''username'',
''password'',
''email'',
...,
)
extra_kwargs = {
''password'': {''write_only'': True},
}
def create(self, validated_data):
user = get_user_model().objects.create_user(**validated_data)
return user
def update(self, instance, validated_data):
if ''password'' in validated_data:
password = validated_data.pop(''password'')
instance.set_password(password)
return super(UserSerializer, self).update(instance, validated_data)
djangorestframework 3.3.x / Django 1.8.x
Seguí adelante e hice mi propia vista personalizada para manejar el registro ya que mi serializador no espera mostrar / recuperar la contraseña. Hice la url diferente del recurso / users.
Mi url conf:
url(r''^users/register'', ''myapp.views.create_auth''),
Mi vista:
@api_view([''POST''])
def create_auth(request):
serialized = UserSerializer(data=request.DATA)
if serialized.is_valid():
User.objects.create_user(
serialized.init_data[''email''],
serialized.init_data[''username''],
serialized.init_data[''password'']
)
return Response(serialized.data, status=status.HTTP_201_CREATED)
else:
return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)
Puede que esté equivocado, pero no parece que deba limitar los permisos en esta vista, ya que querría solicitudes no autenticadas ...
Todas las respuestas hasta ahora crean el usuario y luego actualizan la contraseña del usuario. Esto da como resultado dos escrituras DB. Para evitar una escritura DB innecesaria, configure la contraseña del usuario antes de guardarla:
from rest_framework.serializers import ModelSerializer
class UserSerializer(ModelSerializer):
class Meta:
model = User
def create(self, validated_data):
user = User(**validated_data)
# Hash the user''s password.
user.set_password(validated_data[''password''])
user.save()
return user
Un poco tarde para la fiesta, pero podría ayudar a alguien que no quiera escribir más líneas de código.
Podemos usar el super
método para lograr esto.
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True,
)
class Meta:
model = User
fields = (''password'', ''username'', ''first_name'', ''last_name'',)
def create(self, validated_data):
user = super(UserSerializer, self).create(validated_data)
if ''password'' in validated_data:
user.set_password(validated_data[''password''])
user.save()
return user