5

I'm trying to create a custom user using the Django Rest Framework. I got it to the point to where I can create a regular user, but I'm unsure on how to extend it to the custom user model.

models.py:

from django.db import models
from django.contrib.postgres.fields import ArrayField
from django.contrib.auth.models import User


class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    languages = ArrayField(models.CharField(max_length=30, blank=True))

serializers.py:

from rest_framework import serializers
from django.contrib.auth.models import User


class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email', 'username', 'password')

    def create(self, validated_data, instance=None):
        user = super(UserSerializer, self).create(validated_data)
        user.set_password(validated_data['password'])
        user.save()
        return user

views.py:

@api_view(['POST'])
@permission_classes((AllowAny,))
def create_user(request):
    serialized = UserSerializer(data=request.data)
    if serialized.is_valid():
        serialized.save()
        return Response(serialized.data, status=status.HTTP_201_CREATED)
    else:
        return Response(serialized._errors, status=status.HTTP_400_BAD_REQUEST)

How do I extend the languages field to the UserSerializer to where it can process it? Would it be better to create a signal for every time a user is created it then creates a userprofile automatically?

1
  • You can create custom user model inherit from AbstractBaseUser which will contain languages field. Commented Dec 7, 2017 at 9:45

1 Answer 1

4

You can do it two ways, either by creating a profile Serializer or without it. With Serializer,

class UserProfileSerializer(serializers.ModelSerializer):
    languages = serializers.ListField(child=serializers.CharField(max_length=30, allow_blank=True))

    class Meta:
        model = UserProfile
        fields = ('languages',)

class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    userprofile = UserProfileSerializer(required=False)

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email', 'username', 'password', 'userprofile')


    def create(self, validated_data, instance=None):
        profile_data = validated_data.pop('userprofile')
        user = User.objects.create(**validated_data)
        user.set_password(validated_data['password'])
        user.save()
        UserProfile.objects.update_or_create(user=user,**profile_data)
        return user

without a profile serializer

class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    languages = serializers.ListField(child=serializers.CharField(max_length=30, allow_blank=True), source="userprofile.languages")

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email', 'username', 'password', 'lanugages')


    def create(self, validated_data, instance=None):
        profile_data = validated_data.pop('userprofile')
        user = User.objects.create(**validated_data)
        user.set_password(validated_data['password'])
        user.save()
        UserProfile.objects.update_or_create(user=user,**profile_data)
        return user
Sign up to request clarification or add additional context in comments.

8 Comments

For the first solution, I'm getting a { "profile": [ "This filed is required"] } response from postman when I send a post request with languages as a field and also with profile as a field. And then with the second solution, I'm getting a module 'rest_framework.serializers' has no attribute 'ArrayField' error.
For the first solution, you need to send it as 'profile': {'languages':[]} , for second you need DRF 3.1 and above versions beacuse ArrayField support is included 3.1 . what is your DRF version ?
The version is 3.7.3. I'm trying your suggestion for the profile, but it still isn't working. I have the key as profile and the value as {'languages': ["test"]} and it gives me the same output.
I got the second one to work by changing the ArrayField to ListField, but now it is saying Cannot assign "{'languages': ['"test","test"']}": "User.userprofile" must be a "UserProfile" instance. and it's a problem with the line user = super(UserSerializer, self).create(validated_data)
I tried that and I'm still getting the same error. Any idea on why the profile solution isn't working?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.