Django REST framework 3.xx custom model extension

I am trying to expand the framework of Django rest (version 3.xx) with the fields gender , created_at , updated_at , which are defined in a separate model called UserProfile . When I try to update an instance of the UserProfile model, including a nested instance of the User model, it only updates the instance of UserProfile ( gender, updated_at fields ). So basically I want to update also the email, first_name and last_name fields from the User model

models.py:

 class UserProfile(models.Model): user = models.OneToOneField(User, primary_key = True, related_name = 'profile') gender = models.CharField(choices = GENDERS, default = 2, max_length = 64) created_at = models.DateTimeField(auto_now_add = True) updated_at = models.DateTimeField(auto_now = True) def __unicode__(self): return self.user.username @receiver(post_save, sender = User) def create_profile_for_user(sender, instance = None, created = False, **kwargs): if created: UserProfile.objects.get_or_create(user = instance) @receiver(pre_delete, sender = User) def delete_profile_for_user(sender, instance = None, **kwargs): if instance: user_profile = UserProfile.objects.get(user = instance) user_profile.delete() 

serializers.py:

 class UserProfileSerializer(serializers.ModelSerializer): id = serializers.IntegerField(source = 'pk', read_only = True) username = serializers.CharField(source = 'user.username', read_only = True) email = serializers.CharField(source = 'user.email') first_name = serializers.CharField(source = 'user.first_name') last_name = serializers.CharField(source = 'user.last_name') class Meta: model = UserProfile fields = ( 'id', 'username', 'email', 'first_name', 'last_name', 'created_at', 'updated_at', 'gender', ) read_only_fields = ('created_at', 'updated_at',) def update(self, instance, validated_data): #user = User.objects.get(pk = instance.user.pk); user = instance.user user.email = validated_data.get('user.email', user.email) user.first_name = validated_data.get('user.first_name', user.first_name) user.last_name = validated_data.get('user.last_name', user.last_name) user.save() instance.gender = validated_data.get('gender', instance.gender) instance.save() return instance def create(self, validated_data): user_data = validated_data.pop('user') user = User.objects.create(**user_data) profile = UserProfile.objects.create(user = user, **validated_data) return profile 

views.py:

 class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer class UserProfileViewSet(viewsets.ModelViewSet): queryset = UserProfile.objects.all() serializer_class = UserProfileSerializer 
+6
source share
2 answers

Here is how I did it:

 def update(self, instance, validated_data): # First, update the User user_data = validated_data.pop('user', None) for attr, value in user_data.items(): setattr(instance.user, attr, value) # Then, update UserProfile for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() return instance 

Basically, I looked at the source code for serializers ( here, line 800 ) and modified it to fit my needs.

Good luck.

+4
source

A small modification of the above code replacing None with {}

Since the "NoneType" object does not have the "items" attributes

 def update(self, instance, validated_data): # First, update the User user_data = validated_data.pop('user', {}) for attr, value in user_data.items(): setattr(instance.user, attr, value) # Then, update UserProfile for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() return instance 

There is another way that I implement that takes care of validation. I implement it to handle PATCH

 class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('email', 'first_name', 'last_name') class ProfileSerializer(serializers.ModelSerializer): email = serializers.CharField(source='user.email') first_name = serializers.CharField(source='user.first_name') last_name = serializers.CharField(source='user.last_name') class Meta: model = Profile exclude = ('user',) def update(self, instance, validated_data): user_data = validated_data.pop('user', {}) user_serializer = UserSerializer(instance.user, data=user_data, partial=True) user_serializer.is_valid(raise_exception=True) user_serializer.update(instance.user, user_data) super(ProfileSerializer, self).update(instance, validated_data) return instance 
+1
source

Source: https://habr.com/ru/post/984703/


All Articles