Add Confirm Password Field to UserSerializer in Django Rest Framework
I'm pretty new to the Django Rest Framework in general, but I had a hell of a time figuring out how to add a confirm_password
field to my UserSerializer
model.
The currently suggested methods seem overcomplicated for what I was wanting to do - which is just confirm and validate the user's password!
Eventually I realized I could just make a new Serializer that only handled my registration fields. I'm not sure if this is the best way to do it, but it seems more straightforward than subclassing a field and making my own.
Here's my eventual solution - I created a UserRegistrationSerializer
class that's not tied to a model. This allowed me to add whatever fields I wanted without worrying about adding a non-model field to the UserSerializer
.
from rest_framework import serializers, viewsets
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework.decorators import (api_view, permission_classes, list_route)
from django.http import Http404, HttpResponseForbidden
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'first_name', 'last_name',)
write_only_fields = ('username',)
def validate(self, data):
# Making sure the username always matches the email
email = data.get('email', None)
if email:
data['username'] = email
return data
class UserRegistrationSerializer(serializers.Serializer):
email = serializers.EmailField()
first_name = serializers.CharField(required=False)
last_name = serializers.CharField(required=False)
password = serializers.CharField()
confirm_password = serializers.CharField()
def validate_email(self, email):
existing = User.objects.filter(email=email).first()
if existing:
raise serializers.ValidationError("Someone with that email "
"address has already registered. Was it you?")
return email
def validate(self, data):
if not data.get('password') or not data.get('confirm_password'):
raise serializers.ValidationError("Please enter a password and "
"confirm it.")
if data.get('password') != data.get('confirm_password'):
raise serializers.ValidationError("Those passwords don't match.")
return data
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
@list_route(methods=['post'], permission_classes=[AllowAny])
def register(self, request):
# Validating our serializer from the UserRegistrationSerializer
serializer = UserRegistrationSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Everything's valid, so send it to the UserSerializer
model_serializer = UserSerializer(data=serializer.data)
model_serializer.is_valid(raise_exception=True)
model_serializer.save()
return Response(model_serializer.data)
@list_route(methods=['get'])
def info(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)
def list(self, request):
user = request.user
if not user or not user.is_superuser:
return HttpResponseForbidden()
return super(UserViewSet, self).list(request)
def update(self, request, pk=None):
user = User.objects.filter(id=pk).first()
if not user or request.user != user:
return HttpResponseForbidden()
return super(UserViewSet, self).update(request)
Like I said: I'm new to Django Rest Framework, and this might be dumb. Please let me know if there's a better approach!