Writing APIs on top of Django

April 5th, 2007 09:40

Django provides a very neat filter method for retrieving results from the database. This method allows you to specify matching criteria for each field in a model (and any of the models related via a foreign key). Take the following model for example:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=30)

The following call will return all of the Person instances that have ‘Joe’ as their first_name:

Person.objects.filter(first_name='Joe')

and this call will return all of the Person instances that have ‘Joe’ as their first_name and ‘Bloggs’ as their last_name:

Person.objects.filter(first_name='Joe', last_name='Bloggs')

I like to keep all database calls in one module for abstraction. For example, db.py:

from myproject.models import Person

def get_person(fname=None, lname=None):
  if fname and lname:
    return Person.objects.filter(first_name=fname, last_name=lname)
  elif fname:
    return Person.objects.filter(first_name=fname)
  elif lname:
    return Person.objects.filter(last_name=lname)
  else:
    return None

Using this approach to get all the ‘Bloggs’ records would require a call like so:

db.get_person(None, 'Bloggs)

The first parameter as None isn’t so great is it.

My solution to this style of problem is to use keyword arguments as the only parameter to my db.py functions. This allows great flexibility and uses Django’s filter much more effectively. Here’s my new db.py:

from myproject.models import Person

def get_person(**kwargs):
    return Person.objects.filter(**kwargs)

The call to retrieve all ‘Bloggs’ records now becomes:

db.get_person(last_name='Bloggs')

For this trivial example it would probably be easier to stick to the named parameters example, but when you have models with a large number of fields I find the keyword arguments approach works brilliantly.

Leave a Reply