User Tools

Site Tools


devel:blueprints:refactor-mod-python-to-django

Specification: https://blueprints.launchpad.net/nav/+spec/refactor-mod-python-to-django

Refactor mod_python based web apps to Django based

The mod_python project is dead, its recommended successor is mod_wsgi. Much of the legacy web apps in NAV interface directly with the mod_python API at a low level. These systems should all be refactored to be served through Django instead, so we can be independent of the actual low-lever web server technology being used. A separate blueprint for each mod_python-interfacing web app should be created, and this blueprint should be udpated to depend on all of those.

A typical mod_python handler in NAV

A mod_python handler is a Python module containing a function called handler(). The handler function takes a single argument, a mod_python request object. A typical handler in NAV code will examine the request object and return some output based on the request.

Often, the handler will include its own dispatch function - it performs varying actions based on the request's URI. The dispatch function often comes in the form of a giant if/elif/else construct, or, if you're lucky, it delegates each accepted URI pattern to a separate handler/view function.

A handler does its work, the writes some output back to the client by using the request object's .write() method. The handler function then must return a response status code, typically mod_python.apache.OK (which is equal to 200).

NAV's handlers will typically create an instance of a Cheetah template, fill it, get it's output via the respond() method and write this to the request object.

Scope

Refactoring a mod_python handler is limited to the parts that use mod_python in some way. It is not necessary to ditch Cheetah templates in favor of Django templates, nor ditch pure SQL and legacy db connection in favor of Django's ORM.

Suggested refactoring steps

The goal is most likely to get rid of the handler() function altogether, by splitting its functionality into separate view functions, which can later be attached to a Django urlconfig.

  • Split a large handler() function's dispatch construct by delegating each URI or action to a separate view function. Confirm that this works before proceeding.
  • Deconstruct the URI dispatcher into a Django urlconfig.
  • Refactor each of the newly created view functions:
    • Usage of mod_python's FieldStorage class, or NAV's nav.web.URI.URI class, to extract GET/POST parameters must be refactored to use the GET, POST or REQUEST attributes of the incoming Django request structure.
    • Create a HttpResponse object, feeding it the output of the template's respond() method, and return this response object instead of an apache.OK.

A typical handler ends with something like this:

req.write(template.respond())
return apache.OK

Which can be turned into:

return HttpResponse(template.respond())

The HttpResponse can also adjust the response code and the content-type of the output (which defaults to text/html). Django also has other HttpResponse subclasses for returning specific response codes, such as Http404.

Gotchas

  • A legacy handler's URLs may already have been configured with view names in the nav.django.urls.urlbuilder module, in order for Django apps and templates to easily create reverse links to these systems. These config items must be moved in to your new urlconfig.

Example

Examine these changesets:

:!: It's probably better to portion out your refactoring in multiple changesets which make your changes easier to follow. That's one of the things DVCS'es are for.

devel/blueprints/refactor-mod-python-to-django.txt · Last modified: 2012/10/03 08:29 by morten