Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.

Download
ActivePython
INSTALL>
pypm install django-conneg

How to install django-conneg

  1. Download and install ActivePython
  2. Open Command Prompt
  3. Type pypm install django-conneg
 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
0.7.3
0.9.3Never BuiltWhy not?
0.7.3 Available View build log
0.6 Available View build log
0.5 Available View build log
0.4 Available View build log
0.3 Available View build log
0.2.2 Available View build log
0.2.1 Available View build log
0.2 Available View build log
0.1.3 Available View build log
0.1.2 Failed View build log
Windows (64-bit)
0.7.3
0.9.3Never BuiltWhy not?
0.7.3 Available View build log
0.6 Available View build log
0.5 Available View build log
0.4 Available View build log
0.3 Available View build log
0.2.2 Available View build log
0.2.1 Available View build log
0.2 Available View build log
0.1.3 Available View build log
0.1.2 Failed View build log
Mac OS X (10.5+)
0.7.3
0.9.3Never BuiltWhy not?
0.7.3 Available View build log
0.6 Available View build log
0.5 Available View build log
0.4 Available View build log
0.3 Available View build log
0.2.2 Available View build log
0.2.1 Available View build log
0.2 Available View build log
0.1.3 Available View build log
0.1.2 Failed View build log
Linux (32-bit)
0.9.2
0.9.3Never BuiltWhy not?
0.9.2 Available View build log
0.7.3 Available View build log
0.6 Available View build log
0.5 Available View build log
0.4 Available View build log
0.3 Available View build log
0.2.2 Available View build log
0.2.1 Available View build log
0.2 Available View build log
0.1.3 Available View build log
0.1.2 Failed View build log
Linux (64-bit)
0.9.3 Available View build log
0.9.2 Available View build log
0.7.3 Available View build log
0.6 Available View build log
0.5 Available View build log
0.4 Available View build log
0.3 Available View build log
0.2.2 Available View build log
0.2.1 Available View build log
0.2 Available View build log
0.1.3 Available View build log
0.1.2 Failed View build log
 
License
BSD
Lastest release
version 0.9.3 on Jan 9th, 2014

This project provides a simple and extensible framework for producing views that content-negotiate in Django.

Prerequisites

This library depends on Django 1.3, which you can install using your package manager on recent distributions, or using pip:

pip install -r requirements.txt

pip is called pip-python on Fedora. It is generally provided by a python-pip package.

Using

To define a view, do something like this:

from django_conneg.views import ContentNegotiatedView

class IndexView(ContentNegotiatedView):
    def get(self, request):
        context = {
            # Build context here
        }

        # Call render, passing a template name (without file extension)
        return self.render(request, context, 'index')

This will then look for a renderer that can provide a representation that matches what was asked for in the Accept header.

By default ContentNegotiatedView provides no renderers, so the above snippet would always return a 405 Not Acceptable to tell the user-agent that it couldn't provide a response in a suggested format.

To define a renderer on a view, do something like this:

import json

from django.http import HttpResponse

from django_conneg.decorators import renderer

class JSONView(ContentNegotiatedView):
    @renderer(format='json', mimetypes=('application/json',), name='JSON')
    def render_json(self, request, context, template_name):
        # Very simplistic, and will fail when it encounters 'non-primitives'
        # like Django Model objects, Forms, etc.
        return HttpResponse(json.dumps(context), mimetype='application/json')

Note

django-conneg already provides a slightly more sophisticated JSONView; see below for more information.

You can render to a particular format by calling render_to_format() on the view:

class IndexView(ContentNegotiatedView):
    def get(self, request):
        # ...

        if some_condition:
            return self.render_to_format(request, context, 'index', 'html')
        else:
            return self.render(request, context, 'index')
Forcing a particular renderer from the client

By default, a client can request a particular set of renderers be tried by using the format query or POST parameter:

GET /some-view/?format=json,yaml

The formats correspond to the format argument to the @renderer decorator.

To change the name of the parameter used, override _format_override_parameter on the view class:

class MyView(ContentNegotiatedView):
    _format_override_parameter = 'output'
Providing fallback renderers

Sometimes you might want to provide a response in some format even if the those in the Accept header can't be honoured. This is useful when providing error responses in a different format to the client's expected format. To do this, set the _force_fallback_format attribute to the name of the format:

class MyView(ContentNegotiatedView):
    _force_fallback_format = 'html'

If a client doesn't provide an Accept header, then you can specify a default format with _default_format:

class MyView(ContentNegotiatedView):
    _default_format = 'html'
Built-in renderer views

django_conneg includes the following built-in renderers in the django_conneg.views module:

  • HTMLView (renders a .html template with media type text/html)
  • TextView (renders a .txt template with media type text/plain)
  • JSONView (coerces the context to JavaScript primitives and returns as application/json)
  • JSONPView (as JSONView, but wraps in a callback and returns as application/javascript)

Using these, you could define a view that renders to both HTML and JSON like this:

from django_conneg.views import HTMLView

class IndexView(JSONView, HTMLView):
    def get(self, request):
        # ...
        return self.render(request, context, 'index')

Accessing renderer details

The renderer used to construct a response is exposed as a renderer attribute on the response object:

class IndexView(JSONView, HTMLView):
    def get(self, request):
        # ...
        response = self.render(request, context, 'index')
        response['X-Renderer-Format'] = response.renderer.format
        return response

Renderer priorities

Some user-agents might specify various media types with equal levels of desirability. For example, previous versions of Safari and Chrome used to send an Accept header like this:

application/xml,application/xhtml+xml,text/html;q=0.9,
text/plain;q=0.8,image/png,*/*;q=0.5

Without any additional hints it would be non-deterministic as to whether XML or XHTML is served.

By passing a priority argument to the @renderer decorator you can specify an ordering of renderers for such ambiguous situations:

class IndexView(ContentNegotiatedView):
    @renderer(format='xml', mimetypes=('application/xml',), name='XML', priority=0)
    def render_xml(request, context, template_name):
        # ...

    @renderer(format='html', mimetypes=('application/xhtml+xml','text/html), name='HTML', priority=1)
    def render_html(request, context, template_name):
        # ...

As higher-numbered priorities are preferred, this will result in HTML always being prefered over XML in ambiguous situations.

By default, django-conneg's built-in renderers have a priority of 0, except for HTMLView and TextView, which each have a priority of 1 for the reason given above.

Improved 40x response handling

Django provides a couple of useful exceptions, Http404 and PermissionDenied, which you may want to use in your application. However, it's only possible to customise the 404 site-wide (either by providing a 404.html template, or by setting handler404 in your urlconf), and until Django 1.4 comes out, PermissionDenied will always result in a very spartan error page.

django-conneg provides an ErrorCatchingView which you can use as a mixin to customise the rendering of responses for these error situations:

from django_conneg.views import HTMLView, ErrorCatchingView

class IndexView(HTMLView, ErrorCatchingView):
    # ...

You can then customise error responses in one of the following ways:

  • overriding the ``conneg/(forbidden|not_found|not_acceptable).(html|txt) templates

    System Message: WARNING/2 (<string>, line 196); backlink

    Inline literal start-string without end-string.

  • overriding error_403, error_404 or error_406 methods on the view

  • overriding the error_template_names attribute to specify a non-standard template name:

In the latter case, you can do something like:

import httplib
from django.util.datastructures import MergeDict
from django_conneg.views import HTMLView, ErrorCatchingView

class IndexView(HTMLView, ErrorCatchingView):
    # Provide a view-specific 404 page. Use MergeDict to use django_conneg's
    # defaults for other types of errors.
    error_template_names = MergeDict({httplib.NOT_FOUND: 'foo/404'},
                                     ErrorCatchingView.error_template_names)
    # ...

Running the tests

django-conneg has a modest test suite. To run it, head to the root of the repository and run:

django-admin test --settings=django_conneg.tests.settings --pythonpath=.

If you don't have Django, you'll need to install it as detailed in the Prerequisites section above.

Subscribe to package updates

Last updated Jan 9th, 2014

Download Stats

Last month:9

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.