django: Fat models and skinny controllers? django: Fat models and skinny controllers? python python

django: Fat models and skinny controllers?


MVC is not a universal solution and most of the time it's done wrong and can't keep its promises: in practice modifying a model will require modifications in the controller as well, because it's done wrong. If you really want loose coupling between Model and Controller then - and people usually ignore that - you have to use a service pattern (open as image). Which almost nobody actually does.

Instead of blindly adhering to the MVC fuss/pseudo-pattern in the PHP world, Django takes a pragmatic approach. Because in the common reality of software development, the developer programs things for the user to see. Then the user (your boss, client, customers ...) will "see" your work, and eventually give his opinion about how he wants to "see" it in the end. By using Django, the developer can take a more "view oriented" development pattern and guess what: it makes deadlines easier to respect and users more satisfied. If you think about it, it has its "nosql-ish" idea that the view (general view, not django view) should be the boss of what's going on behind the scenes.

I'd like to thank Django for not doing MVC wrong, unlike 99% of the PHP MVC implementations out there.

On the other hand, Django is the only framework that allows proper isolation between applications. Each application can have:

  • models
  • views
  • templates
  • urls
  • static files
  • tests
  • forms
  • optional addons (admins, filters for ajax-selects, permissions for django-authority, notifications for django-notifications, etc, etc)

So even if your models/views/templates will be tied, your project can be relevantly divided in small (also reads: easy to maintain) and loosely coupled applications. Only related models/views/templates/stuff are tied together. A big fat models script with a big fat views and urls script is not what you want in Django. For example, you don't want two model classes like Article and FootballMatch to live together, you want to make an "articles"/"blog" app and a "sport" app which can live independently. Of course sometimes they must be tied, in that case it's doable at the project level in 90% of the cases (you'd make another app, "blog_sport" if you happened to need to tie in models or templatetags).

For example, it's a super common practice to define a get_absolute_url() method in the Model class. Yes, your model class which in theory has to contain only business logic, is now tied with your urls definition. How bad is this in practice ?!! Well actually it's brilliant because it takes two seconds to add this method and you can then use it anywhere you use a model: be it in views or templates. Also, other applications (e.g. django.contrib.admin) will use it.

Another slightly more complicated example of Django brilliance is that queries are lazily evaluated. Which means, your view function/class will define a query like blog_list = Blog.objects.all(), but the query will actually be executed in the template if it calls like {% for blog in blog_list %}. So business logic happens in the template in that case, and if something fails before the rendering of the template: you saved a query. But that's not all, if your template just displays a count {{ blog_list.count }}, the select query will not be spawned at all and just a count query will be executed. The "general view" decides what business logic is needed. That's far from the promises of MVC but be honest: how practical is that ?

My point is that you can apply theory the wrong way, do it right (which reduces your choice to like 5 web frameworks all languages included), or just get to the point in an elegant and pragmatic way to get your job done the Zen way in no time: that's Django's choice.


It depends of what your application is about, but the beauty of Django is that it does not enforce you to put your logical code in your views or in your models, this is your call.

If you think that some logic is strongly related to your model then you can make a method of it. The rule (for me) is that your model should be agnostic about the environment (web-app, Crontab running a manage command, etc).

My policy is to try to put the bare minimum in my models.

By the way, you don't plan to handle request and sessions in your models don't you ? that is a bad idea.


My biggest problem with Django is that they seem to break the MVC pattern by adding the Forms layer. Most of the documentation induces you to place validation logic in the forms, and the fact that model validators are only called by form saves only reinforces this convention. But it is a bad convention in my opinion because, after all, too often what is being validated is data that will be converted to a model.

The best example of how this is bad is if you think about converting a traditional Django project to a API-centered project with Django Rest Framework and a separate front-end client that just consumes this API. Instead of just leaving your models intact and preserving a lot of business logic, you'll have to go trough your forms and move all the logic to serializers (unfortunately, Django Rest Framework also follows Django's broken MVC pattern and adds an extra "serializer" layer).

I think the fat models approach is the way to go. More information about how to implement it in Django here.