Reading through some common Django books and tutorials, you will come upon the advice to encapsulate your ORM-related business logic inside custom model managers and custom querysets.
In this article, I will try to persuade you no to. Or at the very least, to persuade you that the bar should be very high for introducing those constructs.
What are custom managers / querysets?
TODO
The stated benefits:
- DRY principle
- High level logic is clear
- Codifies field semantics of a model – you can see how to interpret certain fields
My beef with them
Beef #1: Mixed semantics
If you app grows beyond the starting phase, you model will certainly be used in multiple apps. E.g. if you have a content taxonomy model, it might be used for recommending similar content, and it might be used for determining user’s interests.
Beef #2: Now I have to learn your custom DSL
In a Django project, Django’s ORM is the common language between developers. By introducing custom manager methods, now you’re forcing me to use them instead of the ORM. Now I can no longer glance at the function and see all queries. Instead, I have to jump around the file(s) trying to piece together what’s going on.
Beef #3: Nobody knows about them
Use cases come and go. Unless you’re the sole developer on the project, you can’t keep up with the influx of helper methods on the model. Even you might forget about them. If the project is even of medium size, no one can keep up with the influx of helper methods on the custom manager.
What to do instead?
There is a place for the custom manager methods, but the bar for promoting a functionality there has to be extremely high. The criteria are:
- very important to get it right
- complex
- used all over the place
If your functionality doesn’t meet all of these criteria, it would probably be better for it to live in the app’s utils.py, the service layer or on the model itself.