Have you heard this advice?
You should follow the “Fat models / Skinny views Philosophy”
I think the logic should be in the model
And then, you hear some other advice that confuses you, Right? Have you ever heard this?
Fat models aren’t necessarily a good thing…
Which advice is correct? How do you proceed now that you’re all confused and frustrated at all your bloated models?
You don’t want bloated models though…
You know architecture is important. You know that fat models are preferable to fat views. But, you’re confused because you also have a very messy and bloated model that is getting harder and harder to maintain!
That’s why you really shouldn’t have fat models OR fat views. Developers have a hard time following strict dogma because there are always exceptions to the rule.
So, how can YOU break up your Django models into separate and clean utility classes? How do you clean up your model bloat? Create a custom manager!
Why use a Custom Manager?
Let’s assume you have a model that looks like the following:
class Person(models.Model): email = models.EmailField(max_length=250) first_name = models.CharField(max_length=45) last_name = models.CharField(max_length=45)
You might be tempted to write a function that gets a Person by “email”, then you might write a similar function to retrieve a Person by “last_name”
def get_person_by_email(email): return Person.objects.get(email=email) def get_person_by_last_name(last_name): return Person.objects.get(last_name=last_name)
Then, over time, you decide that it would be awesome if you could get all the people in your system with similar domain names in their emails. I want a count of all the people who signed up for my services that have “gmail” email addresses. You could do something like this:
def count_people_by_email_domain(domain): return len(Person.objects.filter(email__endswith="domain"))
You could see that you might have an infinite number of small functions that can manipulate the data anyway that you see fit.
Why not put those functions inside a custom Manager class instead?
That way, instead of writing a bunch of tiny functions and having to import them everywhere you need them, all you have to do is import the model and run the function on the model’s custom Manager class instead!
Let me show you what I mean.
from models import Person # using a custom Manager on email... people = Person.emails.filter_domain(domain) person = Person.emails.get(email) # using a custom Manager on last_name... person = Person.last_names.get(last_name) # etc...
How to Implement a custom manager…
Have I sold you on Custom Managers yet? The great news is that you can break your models up into a bunch of small, specific Manager classes and use them on your models.
Here is a simple Manager class that you can try out right now on our Person Model.
from django.db import models # maybe through your Manager classes into "managers.py" class EmailManager(models.Manager): def filter_domain(self, domain): return super(EmailManager, self).get_queryset().filter(email__endswith=domain) def get(self, email): return super(EmailManager, self).get_queryset().get(email=email) # models.py class Person(models.Model): # our model data... emails = EmailManager()
That’s how you create a manager that encapsulates most of the tiny functions laying around your model. Just throw them into a customer Manager, and you’ll be much happier and so will your models!
What do you do after the Official Django Tutorial?
Here's what you'll learn:
- Start writing tests
- Increase the size / complexity of the Polls application.
- Learn how to code in Django by reading the Django source code.
- Finding code snippets to use in your website by reading the code of other websites.
- Deploying on Heroku and AWS.