December 9, 2015
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 just created a UserRegistration 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)
As I said: I’m pretty new to DRF, but hopefully this helps anyone Googling to their wit’s end like I was.