python - tutorial - partial update django rest framework
Amplíe el modelo de usuario Django REST framework 3.xx (2)
Así es como lo hice:
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
Básicamente, investigué el código original para serializers
( aquí, línea 800 ) y lo modifiqué para que se ajustara a mis necesidades.
Buena suerte.
Estoy intentando ampliar el marco de reposo Django (versión 3.xx) con los campos gender
, created_at
, updated_at
que están definidos en un modelo separado llamado UserProfile
. Cuando intento actualizar la instancia del modelo UserProfile
, incluida la instancia anidada del modelo de User
, solo se actualiza la instancia UserProfile
( gender, updated_at fields
). Básicamente, lo que quiero lograr es poder actualizar también los campos de email, first_name and last_name
del modelo de User
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
Una ligera modificación al código anterior reemplazando el None con {}
Porque el objeto ''NoneType'' no tiene atributos ''items''
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
Hay otra manera que estoy implementando que se ocupa de la validación. Lo estoy implementando para manejar 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