You want to create REST services with Django and understand the available options.
To create a REST service in Django with a standard view method ensure the data you want to output is serializable to the desired format (e.g. XML or JSON). To serialize data you can use Python's core
json package, the Python
dict2xml package, as well as Django's own
django.core.serializers package which supports serialization to XML and JSON.
To create a REST service response in a standard view method you can use
HttpResponse to output the data directly or the short-cut
render method to send the output to a template for further formatting. Irrespective of the response technique you use, it's important you specify the
content_type argument with a MIME type (e.g.
application/xml) to ensure the calling party knows the type of output. Django also offers
JsonResponse -- which is a shortcut version of
HttpResponse -- that automatically converts data to JSON and uses the
application/json MIME type.
For more elaborate Django REST services projects, you can use the Django REST framework or Django Tastypie framework, both of which have a series of features and constructs designed to shorten the development time of REST services in Django.
Representational state transfer (REST) services or simply RESTful services have become one of the most popular techniques in web development since they first appeared in the year 2000. While there's a long background story on REST services which I won't get into here, the appeal and explosive growth of REST services in web development is simply due to how they solve a common problem in an easy and reusable manner.
A REST service provides access to data through an end point or Internet URL making no assumption about who uses it (e.g. a mobile phone, a desktop browser, another program), this means there's no device or environment requirements to access REST services, all you need is Internet access. On top of this, because REST services operate on Internet URLs, they provide a very intuitive access scheme. For example, the REST service URL
/products/ can mean 'get all product data', while the URL
/products/10/20/ can mean get all data for products with a price between 10 and 20 and the URL
/products/drinks/ get all product data in the drinks category. The power of this last approach is there's no steep learning curve (e.g. language syntax, complex business logic) to access REST service variations that solve elaborate data queries.
Because of these features and versatility, REST services work as a reusable data backbone across a wide array of areas and applications. For example, practically the entire web API (Application Programming Interface) world operates around REST web services, because by definition an API must provide a device/environment neutral way for customers to access their functionality. In fact, there's a high-chance most web sites you visit make us of REST services in one way or another, a practice that allows web site operators to reuse the same data and then format it for users on desktop browsers, mobile applications, RSS feeds or any other target like Accelerated Mobile Pages(AMP).
With this brief overview of REST services, let's jump to the first and simplest option available to create REST services in Django.
You can actually create a REST service in Django with just the Django package and Python's core packages, with no need to install any third party package. Listing 1 illustrates a standard Django view method designed to function as a REST service.
The view method in listing 1 first makes a query to get all
Store instances from a database, then creates a list comprehension to generate a list of store names from the resulting query and finally uses Django's
HttpResponse to return a JSON response with the store names using Python's
json package. The design in listing 1 is one of the simplest REST services you can create in Django and has some important points:
Storequery is not used directly in the response, but rather a list comprehension is created first. This is done to serialize the data into an appropriate format. Due to the way Django queries are built, results may not be naturally serializable, so a list comprehension is used to ensure the data is a standard Python dictionary that can be converted to JSON with the
jsonpackage. I provide more details about serialization in the following sidebar and the remainder of this recipe.
HttpResponseconstruct vs. Django's more common
renderhelper method to generate a response. While it would be possible to use Django's
rendermethod and further pass the data to a template to format the response, for most REST services this is unnecessary as responses tend to be raw data (e.g. JSON, XML) that can be generated without a backing template. In addition, notice in listing 1 the
content_typeargument which adds the HTTP
Content-Typeheader telling the requesting party the response is JSON. The HTTP
Content-Typeresponse value is important because it avoids consumers having to guess how to process a REST service response (e.g. another
Content-Typeoption can be
application/xmlfor REST services with XML responses). The HTTP handling in Django view methods recipe contains more details about content types in Django.
|Error: is not JSON/XML serializable|
One of the most common errors you'll likely encounter when you create REST services in Django is the
Now that you have a brief understanding of a simple REST service in Django, let's rework the REST service in listing 1 to make use of parameters so it can return different data results and data formats.
The first thing that's different in listing 2 is the view method can accept a
store_id parameter, allowing the REST service to process a URL request for all stores (e.g.
/stores/rest/) or individual stores (e.g.
/stores/1/rest/ for store number 1). If you're unfamiliar on how to set up Django URLs with parameters, see the previous recipe Access url parameters, extra options and define default url parameters on Django view methods.
Once inside the view method we create a query to get all
Store instances from a database and if there's a
store_id value we further apply a filter on the query to limit the results to the given
store_id. This last query logic is perfectly efficient due to the way Django queries work -- see Understanding a
QuerySet: Lazy evaluation & caching for additional details on this topic.
Next, an inspection is made on the request to see if it has the
type parameter with an
xml value. If a request does match this last rule (e.g.
/stores/rest/?type=xml) then we generate an XML response for the REST service, if it doesn't match this last rule then we generate a JSON response for the REST service.
While the example in listing 2 also uses
HttpResponse and the
content_type argument just like listing 1, notice the data is prepared with Django's
django.core.serializers package which is designed to make data serialization easier -- unlike listing 1 which required pre-processing the query data and then using Python's
json package to complete the process.
The use of
django.core.serializers is very simple in listing 2, we use the
serialize method which expects the serialization type as its first argument (e.g. 'xml' or 'json') and the data to serialize as the second argument (e.g. the
store_list reference which represents the query). There's much more functionality behind the
django.core.serializers package (e.g. filters) that I won't explore here to keep things simple, but figure 1 and 2 show two sample results from listing 2.
As you can see in figures 1 and 2, Django is capable of serializing a query and outputting its result into a valid JSON or XML REST service response with just the few lines in listing 2. It's likely these few lines from listing 2 can take you a long way toward building your own REST services in Django, but if you've never done REST services or plan to use REST services as the centerpiece of an application or web site, you should pause to analyze your requirements.
Because REST services solve a common problem in an easy and reusable manner they tend to suffer from scope creep, that characteristic where changes appear to be never ending and functionality is always 'not quite finished'. After seeing this initial Django REST service example, ask yourself the following questions:
If you said yes to most of the previous questions, then your REST services undertaking is beyond basic. While you could continue building on the example in listing 2 to support all of the previous scenarios -- using a standard Django view method and additional Python packages -- supporting these more elaborate REST services features in Django is a path many have gone down before, to the point there are dedicated packages for just this purpose.
The Django REST framework is now in its 3rd version. Compared to writing your own REST service plumbing as I just described, the Django REST framework offers the following advantages:
These are just some of the core benefits of using the Django REST framework. As you can see, if you plan to create more than a couple of REST services, investing the time to learn the Django REST framework is well worth the time vs. dealing with the scaffolding code necessary to deploy REST services.
The Django Tastypie framework emerged as an alternative to the Django REST framework. Although the Django Tastypie framework is in its 0.13.3 version, don't let the pre-1.0 release number fool you, the Django Tastypie framework has been in development since 2010. Although both the Django Tastypie framework and Django REST framework can potentially produce the same results, the Django Tastypie framework has some of these things going for it:
In the end all options are good. So even though the Django Tastypie framework is not as mainstream as the Django REST framework, if you feel overwhelmed creating REST services with the latter, you can always try out the former to arrive at a faster REST solution than building your REST services from scratch.