I am using Django REST Framework to provide an API for my mobile app. I need send as extra argument when I creating a new Device the email of his owner.
Actually I send a json similar to this:
{"os_type": "AND",
"token": "dfsdfdfsd",
"email": "[email protected]"
}
I need pass some data to the standard ModelViewSet and overrides a little part (extract the email of the owner and associate It with the Device recently created. The problem is that I don't know how to get the id of this new object.
I have this ModelViewSet for my Device model:
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's 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 type Response, and that will render with all de info, but I would like to get the ID in a more elegant or right 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 don't add the field owner in my Device model, because I have already the Owner model that refers to 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 resolve this problem?
You can perform actions after objects are created in Django REST Framework by overriding perform_create
on 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 the create
method on the view, you won't have to worry about any changes being made to the create
method that you will be missing during upgrades. The perform_create
method is the recommended hook, so you don't need to worry about that breaking.
I've also made a few changes to the checks that are being done before the device is created.
ValidationError
is being raised for the 400
error when the email is not passed in with the request. This will produce the same style error messages as other fields, and should be handled by the default exception handler.try...except
has been limited to the DoesNotExist
error that will be triggered if the user gives an invalid email that does not match an owner in the database. This will prevent you squashing edge cases that weren't considered, though the DoesNotExist
and MultipleObjectsReturned
exceptions are the only ones that you should really receive from a get
call.Also, if there is a way to tie the current user making the request (provided in request.user
) to the owner of the device being created (owner
in this case), you might want to skip them providing the email. This depends on how the API is supposed to function of course, because you might be interested in allowing users to tie devices to another owner's account.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With