Chris Pickett

Fat Models

Python > Django | Sept. 20, 2013, 8:29 a.m. | 1 min read

Big is beautiful with Django.

This is the first in a series on Django and fat models, watch this space for more articles.

The Problem

A pattern I see a lot in Django projects is to use the built-in query methods on the default manager of a model. Something like the following:

models.py

class Article(models.Model):
    published = models.BooleanField(default=False)
    published_date = models.DateTimeField()
    ...

views.py

from datetime import datetime
from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    queryset = Article.objects.filter(
        published=True,
        published_date__lte=datetime.now()
    )

Admittedly, by itself this doesn't seem that egregious, but with this example you'll probably end up with this same logic being used in a lot of different places, like the article detail, category detail, archive listing, rss / atom feed, admin, etc.

This is not DRY at all, not to mention that whether or not a article is published isn't logic that a view should be implementing to begin with.

API Legos

I look at the built-in query methods as building-blocks to build your own API. This both allows you to define logic in a single place, keeping yourself DRY, and to implement the logic where it should be, the model.

Rewriting the above in this manner:

models.py

from datetime import datetime
from django import models

class ArticleManager(models.Manager):
    def published(self):
        return self.filter(
            published=True,
            published_date__lte=datetime.now()
        )


class Article(models.Model):
    published = models.BooleanField(default=False)
    published_date = models.DateTimeField()
    ...

    objects = ArticleManager()

views.py

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    queryset = Article.objects.published()

We accomplished several things with this. Not only did we move the logic into the model where it belongs, but we also made the view much cleaner and much more readable.

Comments

comments powered by Disqus