Tidier Model Methods

A common problem with Django models is that your Model’s methods become unwieldy. Dozens of methods tacked on to your Model are handy and all, but:

  1. Your models.py file becomes a big mess.
  2. Your Model’s namespace gets cluttered and it’s hard to tell what’s what.

One technique I’ve become fond of for keeping these organized is to organize these methods into separate classes and then use composition to attach these classes to either an instance or a class.

Here’s a simple example that should give you the idea: let’s say you’ve got a Person model and you have a bunch of methods that apply different formatting to information about this person. You can take all of those formatting-related methods, put them in a class, and then attach them to each Person instance at self.formatters using object composition on the instance:

class Person(models.Model):
    name = models.TextField()
    title = models.TextField()
    address = models.ForeignKey(Address)
    # etc.

    def __init__(self, *args, **kwargs):
        super(Person, self).__init__(*args, **kwargs)
        self.formatters = PersonFormatters(self)

class PersonFormatters(object):
    def __init__(self, person):
        self.person = person

    def greeting(self):
        return "Dear {0} {1}".format(self.person.title, self.person.name)

    def address_label(self):
        return "{0}\n{1}".format(self.greeting(), self.address)

    def insult(self):
        return "You idiot, {0}!".format(self.person.name.upper())

Then you can access all of these methods like person.formatters.greeting(). I get lost whenever I’m inside classes that span hundreds or thousands of lines, so I think this is a pretty nice approach. You could probably go overboard with this and just cause yourself confusion, but in specific cases it can lead to more organized code. There are probably some situations where you could think up certain “Model Helper” classes like this that could be reused across a bunch of different Models as well.