1

I'm new to Django, I'm starting a Django app, I'm using the registration app and Django rest framework, this app will also serve as the backend for an iOS app, I already manage to create users from the iOS app and edit User Profiles from the browser, I need help to find an approach that lets the user edit his profile details once he is logged in. I tried setting a lookup_field like "user.username" to the UserProfileViewSet so I could access the UserProfile object and edit it, but that didn't work.

I also thought I could somehow return the user id after logging in and use this id to reference the userprofile I wanna edit but it does not seem practical at all. What do you think??

Other way I found to do this is by calling user.get_profile() but I don't know how I can make this work from the iOS app.

Here is my UserProfile Model, and serializers, any help would be great. Thanks

class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True)
# Extra attribuets
pagetitle = models.TextField(null=False)
location = models.TextField(null=True)
website = models.TextField(null=True)
bio = models.TextField(null=True)
sex = models.TextField(null=True)
birthdate = models.DateField(null=True)
def __unicode__(self):
    return "%s's profile" % self.user

def create_profile(sender, instance, created, **kwargs):
    if created:
        profile, created= UserProfile.objects.get_or_create(user=instance)

post_save.connect(create_profile, sender=User)


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('username','email','password')

class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
    user = UserSerializer(many=False)
    class Meta:
        model = UserProfile
        fields = ('user','bio')

I create the UserProfile using a signal like this

def create_profile(sender, instance, created, **kwargs):
    if created:
        profile, created= UserProfile.objects.get_or_create(user=instance)

post_save.connect(create_profile, sender=User)
Andrespch
  • 370
  • 3
  • 16

2 Answers2

1

You didn't post your ViewSet code, so I have to guess. But your model should be set to User and your lookup_field should be set to username.

Something like:

class UserViewSet(ModelViewSet):
    model = User
    lookup_field = "username"
Kevin Stone
  • 8,831
  • 41
  • 29
  • Okay, but then what approach should I use? how do I get the current user from the iOS app? Thanks – Andrespch Mar 19 '14 at 09:39
  • I think I just found a way to avoid dealing with this for now, I think I should user AbstractUser instead of having the UserProfile model, am I right? – Andrespch Mar 19 '14 at 12:49
  • 1
    Yeah, you can add fields to an abstract user rather than reference a profile. Usually a profile is more extensible, especially if you might have different types or classes of users. – Kevin Stone Mar 19 '14 at 15:37
  • 1
    To get the current user, you need to add a method to your `ViewSet` to retrieve the current user (stored in django under `request.user`). – Kevin Stone Mar 19 '14 at 15:37
  • I ended up sticking with the onetoonerelation. Now, to reference the userprofile I want to update I'm getting the first the user id, and using this id to update the userprofile since the maintain the same index and hence their ids will always be the same, is this a bad practice? – Andrespch Mar 19 '14 at 15:46
  • 1
    I'd recommend retrieving the user, and then the profile. Your `UserProfile` should add a `related_name` option so you can reference it: `user = models.OneToOneField(User, related_name='profile')`. (unique=True is redundant for OneToOneFields). Then you can just use attribute lookups to get the profile: `profile = User.objects.get(pk=).profile)` – Kevin Stone Mar 19 '14 at 15:49
  • Okay, thank you. Just to be clear, you recommend getting also the profile just to make sure I don't update the wrong profile using the same id as the User object. – Andrespch Mar 19 '14 at 16:00
  • Now I'm trying to get the profile like this, but somehow I keep receiving the user object instead of the userprofile. class CurrentUserProfileView(APIView): def get(self, request): profile = request.user.get_profile() serializer = UserProfileSerializer(profile) return Response(serializer.data) – Andrespch Mar 19 '14 at 16:47
1

For everyone trying to get the profile for a user this is the way I managed to do it thanks to Kevin's help.

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        depth = 1
        fields = ('id','username','email','profile')



class CurrentUserView(APIView):
    def get(self, request):
        serializer = UserSerializer(request.user)
        return Response(serializer.data)

Using a url like this

url(r'^api/current-user',CurrentUserView.as_view(),
        name="current_user"),

You will get an answer like this

"id": 1, 
    "username": "username", 
    "email": "email@email.com", 
    "profile": {
        "id": 1, 
        "user": 1, 
        "bio": "My Bio", 
        "sex": "M", 
        "birthdate": "1987-12-02"
    }
almalki
  • 4,595
  • 26
  • 30
Andrespch
  • 370
  • 3
  • 16