django-tastypie is probably the best at the moment tool for REST API creation in Django applications. The code is on github and documentation is on readthedocs.org.

With tastypie it's easy to create REST API that will allow easy web access to data stored in models - get, update, edit or delete. In this article I'll show some basic usage of tastypie.

Quick start

The installation is typical:
pip install django-tastypie
Next add tastypie to INSTALLED_APPS and that's it.

Now we can start creating resource classes that will be translated into the REST API by tastypie. Documentation presents a "api" folder: APPLICATION_NAME/api/resources.py to store those classes. The location where you can write them isn't fixed. I used api.py file in the application folder.

Creating the API

For this example I used one of my applications that has a JobOffer model holding job offers. Basic resource class for it (or any other model) would look like so:
from tastypie.resources import ModelResource

from jobs import models

class JobOfferResource(ModelResource):
    class Meta:
        queryset = models.JobOffer.objects.all()
        resource_name = 'joboffer'

Each resource class inherits from ModelResource. In the Meta subclass it needs to have queryset defined. The resource_name is optional - can be used to override the resource name used in URLs.

We need the hook the resource class in the urls.py file. Tastypie has it's own URL generator. We register the resource class:

from tastypie.api import Api
from jobs.api import JobOfferResource

v1_api = Api(api_name='v1')
v1_api.register(JobOfferResource())
And add tastypie routing to urls:
(r'^api/', include(v1_api.urls)),
API is done. Under http://localhost:8000/api/v1/joboffer/?format=json we will get a list of entries. Under http://localhost:8000/api/v1/joboffer/schema/?format=json tastypie will show schema of the entry, as well some info about the API (allowe methods for example). Using POST/PUT/DELETE requests you could edit/add/delete entries. The URL structure for a resource is described in the a href="http://django-tastypie.readthedocs.org/en/latest/tutorial.html#hooking-up-the-resource-s">documentation.

Some extra features

We can tune the resource class to fit out needs. For example we can use allowed_methods to limit allowed methods (like only GET to give read-only access). fields can be used to specify which model fields should be available through the API. Here is an example:
class JobOfferResource(ModelResource):
    class Meta:
        queryset = models.JobOffer.objects.all()
        resource_name = 'joboffer'
        allowed_methods = ['get']
        fields = ['id', 'position', 'city', 'published_at']
There are also methods that allow altering data before it's serialized by tastypie. For example dehydrate allows you to add non-model fields into the serialized datasets:
from tastypie.resources import ModelResource

from jobs import models

class JobOfferResource(ModelResource):
    class Meta:
        queryset = models.JobOffer.objects.all()
        resource_name = 'joboffer'
        allowed_methods = ['get']
        fields = ['id', 'position', 'city', 'published_at']

    def dehydrate(self, bundle):
        bundle.data['unicode'] = bundle.obj.__unicode__()
        return bundle

bundle.data is a dictionary with data of a given entry that will be serialized. bundle.obj is the entry object - on which I call one of model methods.

Tastypie also supports authentication. Basic login required access would look like so:
from tastypie.resources import ModelResource
from tastypie.authentication import BasicAuthentication
from tastypie.authorization import DjangoAuthorization

from jobs import models

class JobOfferResource(ModelResource):
    class Meta:
        queryset = models.JobOffer.objects.all()
        resource_name = 'joboffer'
        allowed_methods = ['get']
        fields = ['id', 'position', 'city', 'published_at']
        authentication = BasicAuthentication()
        authorization = DjangoAuthorization()

    def dehydrate(self, bundle):
        bundle.data['unicode'] = bundle.obj.__unicode__()
        return bundle
blog comments powered by Disqus

Categories