Something you should not forget about models manager in Django
While writing a new app for this site, I almost got crazy with model managers (but it's my fault). I wished to have new managers on a model in order to have attributes for getting filtered lists of resources, instead of querying in views; the purpose was also to explore possibilities with managers. Where did I got stuck ?
Let's consider the following model.
1 2 3 4 5 6 7 8 class Article(models.Model): STATES = ( ('draft', 'Draft'), ('masked', 'Masked'), ('published', 'Published'), ) body = models.TextField() state = models.CharField(max_length=32, choices=STATES, default='draft')
I wished to have a manager for each state value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class ArticlePublishedManager(models.Manager): def get_query_set(self): return super(ArticlePublishedManager, self).get_query_set() \ .filter(state='published') class ArticleMaskedManager(models.Manager): def get_query_set(self): return super(ArticleMaskedManager, self).get_query_set() \ .filter(state='masked') class ArticleDraftManager(models.Manager): def get_query_set(self): return super(ArticleDraftManager, self).get_query_set() \ .filter(state='draft')
Then, the managers are defined as model attributes:
1 2 3 4 5 class Article(models.Model): (...) published = ArticlePublishedManager() masked = ArticleMaskedManager() draft = ArticleDraftManager()
Looks good. Everything was fine, then I realize that in the administration site, I can only see published articles. Hum. A quick look at the documentation and I see that I was missing a default manager. Then the model became:
1 2 3 4 5 6 class Article(models.Model): (...) published = ArticlePublishedManager() masked = ArticleMaskedManager() draft = ArticleDraftManager() objects = models.Manager()
But this does not solve the problem in administrative site. I dived again in the documentation and finally understood where the problem lives. The documentation says that when a new manager is added, a default manager has to be defined, and this new default manager is the first declared in the model. Generally, Django uses a lot of conventions; wrongly, I thought that it was enough to define a manager named objects. To get all in order, I just declared objects before published. The final model looks like:
1 2 3 4 5 6 7 8 9 10 11 12 class Article(models.Model): STATES = ( ('draft', 'Draft'), ('masked', 'Masked'), ('published', 'Published'), ) body = models.TextField() state = models.CharField(max_length=32, choices=STATES, default='draft') objects = models.Manager() published = ArticlePublishedManager() masked = ArticleMaskedManager() draft = ArticleDraftManager()
As usual with Django, this is well documented in Custom managers and model inheritance and Modifying initial Manager QuerySets. I did not take care enough when reading documentation... leading to at least one hour lost and lots of self-blaming.