Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to update extended user profile? #51

Closed
Omnipresent opened this issue Feb 10, 2015 · 7 comments
Closed

How to update extended user profile? #51

Omnipresent opened this issue Feb 10, 2015 · 7 comments

Comments

@Omnipresent
Copy link

I had a need to store additional information for the user. So I created a UserProfile model by adding this in my models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    company_name = models.CharField(max_length=100)

Further I made a serializers.py file in my application and added the following to it so that whenever the user is created a UserProfile could be created as well and whenever a user is updated the company_name field would be updated as well.

from rest_framework import serializers
#from django.forms.exceptions import ValidationError
from rest_framework.serializers import ValidationError
from .models import *
from django.contrib.auth import get_user_model
import re


class UserProfileSerializer(serializers.ModelSerializer):
    #follows = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    class Meta:
        model = models.UserProfile
        fields = ('company_name',)

class UserSerializer(serializers.ModelSerializer):
    profile = UserProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # Unless the application properly enforces that this field is
        # always set, the follow could raise a `DoesNotExist`, which
        # would need to be handled.
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.company_name = profile_data.get(
            'company_name',
            profile.company_name
        )
        profile.save()

        return instance

However, the changes I made to serializers.py don't seem to be having any effect.
How would I go about updating the company_name field when the user profile is updated on this url http://localhost:8080/rest-auth/user/ ? FYI, I'm trying all this in the demo application that ships with application.

@jmorrice
Copy link

+1 for supporting extended user profiles!

@mateusz-sikora
Copy link
Contributor

@Omnipresent
I recommend creating fields from UserProfile model directly in UserSerializer, like this:

class UserSerializer(serializers.ModelSerializer):
    company_name = models.CharField(max_length=100)

and then update UserProfile object inside update method.

Your solution will not work because you can update only UserProfile id assigned to User, not fields from UserProfile.

@mateusz-sikora
Copy link
Contributor

@jmorrice You can write your custom serializer to do that.

@mateusz-sikora
Copy link
Contributor

@jmorrice @Omnipresent I added new position in FAQ, should be helpful for both of you http://django-rest-auth.readthedocs.org/en/latest/faq.html (point #2)

@Idanraman
Copy link

@mateusz-sikora I've seen your solution while looking for somthing similar for myself, and tried to come up with somthing a bit more general which doesn't make you add each field seperatly throughout the code. Came up with this -

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True)
    phone_number = models.CharField(blank=True,null=True,max_length=20)
    access_token = models.CharField(blank=True,null=True,max_length=140)
    email_sub = models.BooleanField(default=False)

class UserSerializer(UserDetailsSerializer):
	phone_number = serializers.CharField(source="userprofile.phone_number")
	access_token = serializers.CharField(allow_blank=True,source="userprofile.access_token")
	email_sub = serializers.BooleanField(source="userprofile.email_sub")


	class Meta(UserDetailsSerializer.Meta):
		fields = ['pk', 'username', 'email', 'first_name', 'last_name'] + \
			[f.name for f in UserProfile._meta.get_fields()]
		del fields[fields.index('user')]


	def update(self, instance, validated_data):
		raise_errors_on_nested_writes('update', self, validated_data)
		info = model_meta.get_field_info(instance)
		profile = instance.userprofile
		p_info = model_meta.get_field_info(profile)

		for attr, value in validated_data.items():
			if attr == 'userprofile':
				for attr2, value2 in value.items():
					setattr(profile, attr2, value2)

			elif attr in info.relations and info.relations[attr].to_many:		
				field = getattr(instance, attr)
				field.set(value)
			else:
				setattr(instance, attr, value)
		instance.save()
		profile.save()

		return instance

@rnjailamba
Copy link

@Idanraman do you have this code within a github codebase so that i can understand it fully. For example what is UserDetailsSerializer?

@POD666
Copy link

POD666 commented Jun 30, 2018

class ProfileSerializer(serializers.ModelSerializer):
    avatar = serializers.CharField(source='profile.avatar')
    
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'avatar']

    def save(self, **kwargs):
        profile = self.validated_data.pop('profile')
        instance = super().save(**kwargs)
        Profile.objects.update_or_create(user=instance, defaults=profile)
        return instance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants