Problem : I’m unable to save the both models in database from a single serialzer.
Description : I’m using djoser auth library for registration and authentication. for that i’m using custom django auth user and mapped it with userprofile model. Since i’m using userprofile along with the django user, i have to use custom register serializer.
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_("email address"), unique=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = CustomUserManager()
class UserProfile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="userProfile")
user_guid = models.UUIDField(
default=uuid.uuid4,
unique=True,
editable=False
)
user_type = models.IntegerField(choices=UserType.choices(), default=UserType.BUYER)
wallet_balance = models.FloatField()
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_at' ] # Corrected the ordering syntax
CustomUser = get_user_model()
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['user_guid', 'user_type', 'wallet_balance', 'created_at', 'updated_at']
read_only_fields = ['user_guid', 'created_at', 'updated_at']
class CustomUserCreateSerializer(DjoserUserCreateSerializer):
userProfile = UserProfileSerializer()
class Meta:
model = CustomUser
fields = ['id', 'email', 'password', 'userProfile']
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user_profile_data = validated_data.pop('userProfile')
user = CustomUser.objects.create_user(**validated_data)
UserProfile.objects.create(user=user, **user_profile_data)
return user`
`AUTH_USER_MODEL = 'users.CustomUser'
DJOSER = {
'SERIALIZERS': {
'user_create': 'users.v1.serializers.CustomUserCreateSerializer',
'user': 'users.v1.serializers.CustomUserCreateSerializer',
'current_user': 'users.v1.serializers.CustomUserCreateSerializer',
}
}
Error : raise ValueError( ValueError: Cannot assign “{‘user_type’: 1, ‘wallet_balance’: 0.0}”: “CustomUser.userProfile” must be a “UserProfile” instance.
CustomUserCreateSerializer.Meta.extra_kwargs
for password, because the "write_only" param already set in djoser.serializers.UserCreateSerializer
;create
method, like in this docs, but you need to customize validate
method too.from django.contrib.auth.password_validation import validate_password
from django.core import exceptions as django_exceptions
from djoser.serializers import UserCreateSerializer
from rest_framework import serializers
from rest_framework.settings import api_settings
from .models import UserProfile, CustomUser
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['user_guid', 'wallet_balance', 'created_at', 'updated_at']
read_only_fields = ['user_guid', 'created_at', 'updated_at']
class CustomUserCreateSerializer(UserCreateSerializer):
user_profile = UserProfileSerializer()
class Meta:
model = CustomUser
fields = ['id', 'email', 'password', 'user_profile']
def create(self, validated_data):
profile_data = validated_data.pop('user_profile')
user = CustomUser.objects.create_user(**validated_data)
UserProfile.objects.create(user=user, **profile_data)
return user
def validate(self, attrs):
profile_data = attrs.pop("user_profile")
user = CustomUser(attrs)
profile = UserProfile(user=user, **profile_data)
password = attrs.get("password")
try:
validate_password(password, user)
except django_exceptions.ValidationError as e:
serializer_error = serializers.as_serializer_error(e)
raise serializers.ValidationError(
{"password": serializer_error[api_settings.NON_FIELD_ERRORS_KEY]}
)
attrs["user_profile"] = profile_data
return attrs
user_type
field, cause you didn't show it properly in your question (you can use it as you want).python manage.py shell
Python 3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from my_app.serializers import CustomUserCreateSerializer
>>> data = {"email": "lengthylyova@gmail.com", "password": "SomeInsanePassword123", "user_profile": {"wallet_balance": 0.0}}
>>> serializer = CustomUserCreateSerializer(data=data)
>>> serializer.is_valid(raise_exception=True)
True
>>> serializer.save()
<CustomUser: lengthylyova@gmail.com>
sqlite3 db.sqlite3
sqlite> select * from my_app_userprofile;
1|3c6a03729d6a41f4b719b7a702b06507|0.0|2024-07-30 00:01:36.824563|2024-07-30 00:01:36.824563|1