Duncan
Duncan

Reputation: 49

Unable to create profile from user Serializer (Django-resst-framework)

I have 2 models, Account model as shown

class Account(AbstractBaseUser,PermissionsMixin):
    email = models.EmailField(max_length=100, unique = True)
    username = models.CharField(max_length = 30)
    is_admin = models.BooleanField(default = False)
    is_staff = models.BooleanField(default = False)
    is_active = models.BooleanField(default = False)
    date_joined = models.DateTimeField(auto_now_add = True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = [
       'username'
    ]

and the profile table as shown below

class Profile(models.Model):
    user = models.OneToOneField(Account, on_delete = models.CASCADE)
    avatar = models.ImageField(default = "defaultpic.png", blank = True, null = True, upload_to="MEDIA_FILES" )
    tel = PhoneField(blank=False, null = False)

ProfileSerializer

class ProfileSerializer(serializers.ModelSerializer):
class Meta:
    model = Profile
    fields = [
        'avatar',
        'tel',
    ]

UserSerializer

class AccountSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(read_only = True)

class Meta:
    model = get_user_model()
    fields = [
        'email',
        'username',
        'password',
        'profile'
    ]

    extra_kwargs = {
'password': {'write_only': True},
}

def create(self, validated_data):
    user_password = validated_data.pop('password')
    user = get_user_model()(
    email = validated_data['email'],
    username = validated_data['username']
    )
    user.set_password(user_password)
    user.save()

    user.email_user("Hello world")

    return user

Endpoint to register a new user

@api_view(["POST"]) @permission_classes([AllowAny, ])

def register(request): profSerializer = ProfileSerializer( data = request.data ) serializer = AccountSerializer( data = request.data )

if serializer.is_valid():
    serializer.save()
    serializer.send_mail("Hello")
    return JsonResponse( serializer.data )

else:
    print( serializer.errors )
    return JsonResponse(  { "_err": serializer.errors }  )

My problem now comes in when I send a post request to the registering endpoint, the profile fields remain empty, the avatar field is assigned the default value of default.png. I need the endpoint to create both user account and profile entries whenever a user sign up

The post request to the endpoint is the following JSON

{
      email:"some email",
      username:"username",
      password:"password",
      tel:"tel number",
      avatar:"image"
    }

Upvotes: 1

Views: 145

Answers (1)

Ersain
Ersain

Reputation: 1520

In your AccountSerializer you have set the profile field to read only:

profile = ProfileSerializer(read_only=True)

This means the field will be neglected and will not be shown in request.data.

Then you need a little change in your create method, something like this:

def create(self, validated_data):
    profile_data = validated_data['profile']

    # user creation steps
    ...

    profile = Profile(
        user=user,
        **profile_data
    )
    profile.save()

    return user

rest_framework cannot create related objects by default, this is why you need to create an account instance first, and then create a Profile by yourself

Then, you do not need to serialize request.data with ProfileSerializer in your view, remove the line and change the request body to:

{
    email:"some email",
    username:"username",
    password:"password",
    profile: {
        tel:"tel number",
        avatar:"image"
    }
}

I suggest you learning about nested serializers and how they work

Upvotes: 1

Related Questions