Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework extended user profile

I recently discovered DRF and I'm lost with the quantity of views, viewsets and other possibilities.

I have a Python3/Django 1.8 application with an extended user profile:

from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _


class Profile(models.Model):
    GENDER = (
        ('male', _('MALE')),
        ('female', _('FEMALE')),
    )
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.CharField(default='', max_length=500, null=True, blank=True)
    gender = models.CharField(max_length=10, choices=GENDER, null=True, blank=True)
    city = models.CharField(default='', max_length=30, null=True, blank=True)
    country = models.CharField(default='', max_length=30, null=True, blank=True)

I would like to allow external mobile applications connected with oauth2/token Bearer to get the current connected user's profile through the api and editing it using those routes:

GET or PUT /api/profile GET or PUT /api/user

My first intention was using only one route for manipulate both models (through /api/profile) but I failed and I'm not sure if it's a good practice to mix two models behind one route.

I tried lot of things. My last attempt was to get the profile like this:

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

    password = serializers.CharField(write_only=True)


class UserViewSet(viewsets.ModelViewSet):
    @list_route(methods=['get', 'post'], permission_classes=[permissions.IsAuthenticated])
    def profile(self, request):
        u = User.objects.filter(pk=request.user.pk)[0]
        p = Profile.objects.filter(user=u)[0]
        return Response({"id": u.id, "first_name": u.first_name, "last_name": u.last_name, "email": u.email,
                     "city": p.city, "country": p.country, "bio": p.bio})

    permission_classes = [permissions.IsAuthenticated]
    queryset = User.objects.all()
    serializer_class = UserSerializer


router = routers.DefaultRouter()
router.register(r'users', UserViewSet)

Problem is: I'm failed trying to implement the same thing for PUT requests. Furthermore I would like to do the security and defensive coding part on the API side and in this situation I don't even using the serializers.

Could you guys help me to find the right thing to do? Do you have any tips, suggestions?

Cheers

like image 895
epi.log Avatar asked Apr 08 '16 08:04

epi.log


1 Answers

I think this is what you want:

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ('bio', 'gender', 'city', 'country')


class UserSerializer(serializers.ModelSerializer):

    profile = ProfileSerializer()

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

Or if you want it flat:

class UserSerializer(serializers.ModelSerializer):

    bio = serializers.CharField(source='profile.bio')
    gender = serializers.CharField(source='profile.gender')
    #same for the others

    class Meta:
        model = User
        fields = ('url', 'username', 'password', 'email', 'groups', 'bio', 'gender')

I didn't test it, but should be close to what you want, or close to it at least.

like image 192
Kritz Avatar answered Sep 25 '22 01:09

Kritz