Question

I'm using Django and tastypie to develop a REST API, with a primary key that is a UUIDField from django_extensions. However, making the primary key a UUID isn't playing nicely with tastypie: when I create a resource with POST, the URI it returns is an int, not the UUID, and the provided URI is then unusable since the rest of the API expects the UUID to access a resource.

I think this is because the UUIDField only replaces the value in the UUIDField in Django's pre_save, and tastypie is returning the headers before that happens.

I tried writing a custom get_resource_uri for LocationResource, but the object passed into the function doesn't have a UUID yet (just the normal auto-incrementing integer primary key).

How can I get tastypie to return the correct UUID for a resource? Is there a better way of making a pk a UUID that tastypie will like better?

The model:

from django.db import models
from django_extensions.db.fields import UUIDField

class Location(models.Model):
    """ Stores information about a location. """

    id = UUIDField(primary_key=True)
    path = models.TextField()

    def __unicode__(self):
        return "{uuid}: {path}".format(uuid=self.id, path=self.path)

The tastypie ModelResource (I'm still developing locally so authentication and authorization aren't set up properly yet):

class LocationResource(ModelResource):
    class Meta:
        queryset = Location.objects.all()
        authentication = Authentication()
        authorization = Authorization()

What I'm seeing (JSON formatted for readability):

$ curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"path": "/path/to/directory/"}' http://localhost:8000/api/v1/location/ 
HTTP/1.0 201 CREATED
Date: Tue, 11 Jun 2013 19:59:07 GMT
Server: WSGIServer/0.1 Python/2.7.3
Vary: Accept
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=utf-8
Location: http://localhost:8000/api/v1/location/1/

$ curl --dump-header - -H "Content-Type: application/json" -X GET http://localhost:8000/api/v1/location/1/
HTTP/1.0 404 NOT FOUND
Date: Tue, 11 Jun 2013 19:59:27 GMT
Server: WSGIServer/0.1 Python/2.7.3
Vary: Accept
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=utf-8

$ curl --dump-header - -H "Content-Type: application/json" -X GET http://localhost:8000/api/v1/location/
HTTP/1.0 200 OK
Date: Tue, 11 Jun 2013 19:59:32 GMT
Server: WSGIServer/0.1 Python/2.7.3
Vary: Accept
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Cache-Control: no-cache

{"meta": 
    {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1}, 
 "objects": [
    {"id": "5fe23dd4-d2d1-11e2-8566-94de802aa978", 
     "path": "/path/to/directory/", 
     "resource_uri": "/api/v1/location/5fe23dd4-d2d1-11e2-8566-94de802aa978/"
    }
  ]
}
Was it helpful?

Solution

From my experience, I wouldn't try use UUID with django (as a primary key that is). Perhaps some cleverer people have gotten it to work, but I've spent a few hours trying to get uuids working nicely, but its a real headache. By default django expects primary keys to be integers, and most django extensions make the same presumption.

Tastypie uses django's core resolver to generate the location, so the problem really isn't localised to tastypie. If you want UUIDs to work, you'd probably need to fork django and make your own changes, which is definitely not recommended.

At the end of the day, not having your uuid in your URI shouldn't actually matter too much. the idea of a URI is that its independent of model record, ie a uri doesn't have to contain the primary key of the model. A URI is in itself a unique identifier to a resource (read object), and so it shouldn't be a big concern to you what it looks like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top