Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST framework: Create/Update object using Related Field

I have two models

Auth User model and UserProfile

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')
    name = models.CharField(_lazy(u'Name'), max_length=255)

For which I am using these serializers:

from rest_framework import serializers
from django.contrib.auth.models import User

from oneanddone.users.models import UserProfile

    class UserProfileSerializer(serializers.ModelSerializer):

        class Meta:
            model = UserProfile
            fields = ('name',)


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

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

But on making a post request

requests.post('http://localhost:8000/api/v1/users/', data={"username": "tester", "email": "[email protected]", "profile": [{"name":"testername"}]} ,headers={'Authorization':'Token d81e33c57b2d9471f4d6849bab3cb233b3b30468'}).text

I get the following object with a "null" profile field

u'{"id": 10, "username": "tester", "email": "[email protected]", "groups": [], "profile": null}'

I am not able to figure out how to achieve creation and updation of user profile name along with auth user data. Please let me know how to do this and provide some example for the same.

like image 411
bitgeeky Avatar asked May 19 '14 18:05

bitgeeky


2 Answers

Django REST Framework currently doesn't support nested writes, so you will have to create the UserProfile by overriding create in a ListCreateAPIView:

class UserList(generics.ListCreateAPIView):
    model = User
    serializer_class = UserSerializer

    def create(self, request, *args, **kwargs):
        data = request.DATA

        # note: transaction.atomic was introduced in Django 1.6
        with transaction.atomic():
            user = User.(
                username=data['username'],
                ...
            )
            user.clean()
            user.save()

            UserProfile.objects.create(
                user=user,
                name=data['profile']['name']
            )

        serializer = UserSerializer(user)
        headers = self.get_success_headers(serializer.data)

        return Response(serializer.data, status=status.HTTP_201_CREATED,
                        headers=headers)

Using transaction.atomic will rollback the user creation if the profile doesn't save successfully.

Edit

If you are creating a new user you will likely want to use the create_user method. The code above was intended to show the general case of creating a model instance and a related record in one REST API POST request.

like image 78
Fiver Avatar answered Sep 28 '22 08:09

Fiver


Actually Django Rest Framework has a partial nested support. If you look at the test suite you'll find some. As for bitgeeky question, as said on IRC, this should work. Here's an associated test case: https://github.com/tomchristie/django-rest-framework/blob/2.3.13/rest_framework/tests/test_relations_nested.py#L56

Thinking about this, I think I had this error once. @bitgeeky can you make sure you're sending a json request by adding the content type in the header ? By default posts will be using forms which don't support nested.

like image 39
Xavier Ordoquy Avatar answered Sep 28 '22 06:09

Xavier Ordoquy