Get id of newly created Django Rest Framework object

I am using Django REST Framework to provide an API for my mobile app. I need to send an additional argument when I create a new device via email to its owner.

I am actually sending json like this:

{"os_type": "AND",
 "token": "dfsdfdfsd",
 "email": "sdfdfd@sdfs.com"
}

      

I need to pass some data to the standard ModelViewSet and override a small part (retrieve the owner's email and link it to the newly created device. The problem is I don't know how to get the id of this new object.

I have a ModelViewSet for my device:

class DeviceViewSet(viewsets.ModelViewSet):

    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def create(self, request):
        """
            Overrides the create method in order to get
            extra params: the email of the device owner.
            When this is done, we pass the method to his parent.
        """
        print "creating..."

        created = super(DeviceViewSet, self).create(request)
        print type(created).__name__
        #[method for method in dir(created) if callable(getattr(created, method))]
        return created

      

The "created" object is a Response type that will display all the data, but I would like to get the ID in a more elegant or correct way.

And this is my device model:

class Device(models.Model):
    """
    iOS or Android device, where is installed the app
    """

    ANDROID = 'AND'
    IOS = 'IOS'

    OS_DEVICES_CHOICES = (
        (ANDROID, 'Android'),
        (IOS, 'iOS'),
    )

    os_type = models.CharField(max_length=3, choices=OS_DEVICES_CHOICES)
    token = models.CharField(max_length=1000)

    active = models.BooleanField(default=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

      

I prefer not to add the owner of the field to my device model, because I already have an Owner model that references Device:

class Owner(models.Model):
    name = models.CharField(max_length=200, blank=True, null=True)
    biography = models.TextField(max_length=1000, blank=True, null=True)
    birthday = models.DateField(blank=True, null=True)
    country = models.CharField(max_length=50, blank=True, null=True)
    language = models.CharField(max_length=50, blank=True, null=True)

    email = models.EmailField(blank=True, null=True)

    devices = models.ManyToManyField(Device)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return u'[{0}] {1}'.format(self.id, self.name)

    def __unicode__(self):
        return u'[{0}] {1}'.format(self.id, self.name)

      

How can I solve this problem?

+3


source to share


2 answers


You can perform post-creation actions in the Django REST Framework using an override perform_create

in your view
.

class DeviceViewSet(viewsets.ModelViewSet):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def perform_create(self, serializer):
        from rest_framework.exceptions import ValidationError

        data = self.request.data

        if "email" not in data:
            raise ValidationError({
                "email": "No owner email provided",
            })

        try:
            owner = Owner.objects.get(email=data["email"])
        except Owner.DoesNotExist:
            return Response(
                'No owner with the email ({0}) found'.format(email),
                status=status.HTTP_406_NOT_ACCEPTABLE
            )

        device = serializer.save()

        owner.devices.add(device)

      

By overriding perform_create

instead of a method create

in the view, you don't have to worry about any changes made to the method create

that will be missing during updates. The method perform_create

is the recommended hook, so you don't need to worry about this violation.



I also made a few changes to the checks that run before the device is created.

Also, if there is a way to associate the current user with the request (provided to request.user

) the owner of the device being created ( owner

in this case), you can skip them by specifying Email. address. It depends on how the API is supposed to function, of course, because you might be interested in allowing users to associate devices with a different owner account.

+9


source


Finally, I solved the problem of writing my own code to store the serializer object and get the ID directly.

This is the complete code:



class DeviceViewSet(viewsets.ModelViewSet):

    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def create(self, request):
        """
            Overrides the create method in order to get
            extra params: the email of the device owner.
            When this is done, we pass the method to his parent.
        """
        print "creating..."
        data = request.data
        email = None
        if 'email' in data:
            email = data['email']
        else:
            return Response("No owner email provided", status=status.HTTP_400_BAD_REQUEST)

        try:
            owner = Owner.objects.get(email=email)
        except Exception as e:
            print e
            return Response('No owner with the email ({0}) found, error: {1}'.format(email, e), 
                status=status.HTTP_406_NOT_ACCEPTABLE)


        serializer = DeviceSerializer(data=request.data)
        if serializer.is_valid():
            device = serializer.save()
            print device.id
            owner.devices.add(device)
            #device.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

      

0


source







All Articles