DRF创建用户无Profile字段报错及关联Profile访问问题
Hey there! Let's work through your two issues step by step, using your provided code as context:
Problem 1: KeyError: 'profile' when creating a user without passing the profile field
Root Cause
In your CustomUserSerializer.create() method, you're calling validated_data.pop('profile') directly. If the request doesn't include a profile field, this will throw a KeyError because the key doesn't exist in the validated_data dictionary.
Fix
Modify the create method to safely retrieve the profile data with a default empty dictionary, then create the UserProfile even if no profile data is provided:
def create(self, validated_data): # Use pop with a default empty dict to avoid KeyError profile_data = validated_data.pop('profile', {}) user = CustomUser.objects.create(**validated_data) # Create UserProfile with the retrieved data (empty dict will use model defaults) UserProfile.objects.create(user=user, **profile_data) return user
This way, if no profile field is sent in the request, profile_data will be an empty dictionary, and UserProfile.objects.create() will create a profile with all nullable/blank fields set to their default values (null/empty).
Problem 2: Can't access UserProfile properties via user.profile.age
Root Cause
Looking at your UserProfile model, you've set related_name='userProfile' on the OneToOneField to CustomUser. This means the reverse relationship from CustomUser to UserProfile is named userProfile, not profile. So user.profile doesn't exist—you need to use the correct related name.
Fix Options
You have two straightforward options here:
Option 1: Use the existing related name in your view
Update the line in verifyUserOtp where you try to access the age:
# Replace this: print(user.profile.age) # With this: print(user.userProfile.age)
Option 2: Change the related_name to profile (to match your serializer's field name)
Modify the UserProfile model's OneToOneField to use related_name='profile':
class UserProfile(models.Model): user = models.OneToOneField( CustomUser, primary_key=True, related_name='profile', on_delete=models.CASCADE,) # ... rest of your model fields
This will let you use user.profile.age as expected. Additionally, you should fix the update method in your CustomUserSerializer where you incorrectly reference instance.profile and try to set instance.age (a UserProfile field, not a CustomUser field):
def update(self, instance, validated_data): profile_data = validated_data.pop('profile', {}) # Update user data instance.first_name = validated_data.get('first_name', instance.first_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.email = validated_data.get('email', instance.email) instance.save() # Update user profile profile = instance.profile if not profile: profile = UserProfile.objects.create(user=instance, **profile_data) else: profile.age = profile_data.get('age', profile.age) profile.gender = profile_data.get('gender', profile.gender) profile.save() password = validated_data.get('password', None) if password: instance.set_password(password) instance.save() update_session_auth_hash(self.context.get('request'), instance) return instance
内容的提问来源于stack exchange,提问作者afk

