Handling user registration and subsequent profile creation

I have a custom User model with a role field and respective [Role]Profile models:

class User(AbstractUser):
    role = models.CharField()
    # Other fields

class TeacherProfile(models.Model):
    # profile_picture and other fields

class StudentProfile(models.Model):
    # for now just a reference to the user model
    user = models.OneToOneField(User, ...)

These models have their respective serializers. I am using the djoser library for handling user authentication. Now the default way I use to handle user creation and profile management would be:

  1. Client sends user payload only - stuff like name, email, role etc.
  2. Use post_save signal to create the appropriate profile object by determining the role field.
  3. Then to upload profile related fields, simply send a PATCH request for that profile.

The issue is the client wants to send the whole thing at once. They have a registration form which contains auth fields and also profile fields like profile_pic or about field or whatever. This is what ChatGPT suggested:

class CustomUserCreateSerializer(UserCreateSerializer):
    teacher_profile = TeacherProfileSerializer(required=False)
    student_profile = StudentProfileSerializer(required=False)

    class Meta(UserCreateSerializer.Meta):
        model = User
        fields = (
            "id",
            "email",
            "password",
            "role",
            "first_name",
            "last_name",
            "teacher_profile",
            "student_profile",
        )

    def create(self, validated_data):
        teacher_profile_data = validated_data.pop("teacher_profile", None)
        student_profile_data = validated_data.pop("student_profile", None)

        user = super().create(validated_data)

        # Signals will create the profile automatically, we just update it if data was provided
        if user.role == User.TEACHER and teacher_profile_data:
            profile, created = TeacherProfile.objects.get_or_create(user=user)
            for attr, value in teacher_profile_data.items():
                setattr(profile, attr, value)
            profile.save()
        elif user.role == User.STUDENT and student_profile_data:
            profile, created = StudentProfile.objects.get_or_create(user=user)
            for attr, value in student_profile_data.items():
                setattr(profile, attr, value)
            profile.save()

        return user


class CustomUserCreatePasswordRetypeSerializer(UserCreatePasswordRetypeSerializer):
    teacher_profile = TeacherProfileSerializer(required=False)
    student_profile = StudentProfileSerializer(required=False)

    class Meta(UserCreatePasswordRetypeSerializer.Meta):
        model = User
        fields = (
            "id",
            "email",
            "password",
            "role",
            "first_name",
            "last_name",
            "teacher_profile",
            "student_profile",
        )

    def create(self, validated_data):
        teacher_profile_data = validated_data.pop("teacher_profile", None)
        student_profile_data = validated_data.pop("student_profile", None)

        user = super().create(validated_data)

        if user.role == User.TEACHER and teacher_profile_data:
            profile, created = TeacherProfile.objects.get_or_create(user=user)
            for attr, value in teacher_profile_data.items():
                setattr(profile, attr, value)
            profile.save()
        elif user.role == User.STUDENT and student_profile_data:
            profile, created = StudentProfile.objects.get_or_create(user=user)
            for attr, value in student_profile_data.items():
                setattr(profile, attr, value)
            profile.save()

        return user


class CustomUserSerializer(UserSerializer):
    class Meta(UserSerializer.Meta):
        model = User
        fields = ("id", "email", "role", "first_name", "last_name")

I don't know if this is the right way to go, for some reason it feels wrong. Can anyone suggest how I should handle this. Now the payload looks like this:

{
  "email": "user@example.com",
  "password": "string",
  "role": "admin",
  "first_name": "string",
  "last_name": "string",
  "teacher_profile": {
    "profile_picture": "string",
    "professional_title": "string",
    "location": "string",
    "about": "string",
    "education": "string",
    "achievements": "string",
    "consultation_rate": "51251202",
    "user": 0
  },
  "student_profile": {
    "user": 0
  },
  "re_password": "string"
}
Вернуться на верх