Django Managers, Queryset Managers. Récupérer vos retraités rapidement.

Publié le 21 octobre 2010 par Samuel Martin

Si je voulais faire simple et rapide je vous conseillerais de lire la documentation Django sur les Managers ainsi que la version 1.2. Tout est très bien expliqué. Je me permets ici de réexpliquer rapidement l'intérêt de la chose et de présenter une autre approche, tout aussi intéressante des querysets managers.

Les Managers, est-ce vraiment indispensable ?

Indispensable non mais très utile oui, voyez ça comme un formidable raccourci, dans l'écriture de vos requêtes, hum queryset pardon.

Je reprends volontairement un exemple proche de la doc officielle. Prenons le cas de la gestion de "Personne" class Person(models.Model): avec tout un tas de données confidentielles. Si je souhaite obtenir la liste complète j'utilise tout simplement la méthode suivante Person.objects.all(). Bon et bien maintenant je souhaite obtenir une liste de retraités, facile il suffit de regarder l'âge de chaque personne. Ce qui pourrait ressembler classiquement à : Person.objects.filter(age__gte = 60)

Ceci fonctionne très bien jusqu'à la réforme des retraites et l'obligation du départ à 67 ans.. Ok il suffit de changer 60 par 67 et "astalavista baby". Oui mais niveau maintenance c'est la misère, surtout si on utilise ce filtre au quatre coin de l'application. Magie avec les fameux managers, le queryset/requête devient : Person.retired.all().

Je répète :

  • Person.objects.filter(age__gte = 60) devient Person.retired.all().

En pratique, le code

Classe

Dans models.py

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
    age = models.AgeField()
    
   objects = models.Manager() #pour pas que Django perde la tête
   retired = RetiredManager()  #nouveautés pour gérer les retraités



Managers

A placer dans models.py ou managers.py si vous êtes ordonnés !

class RetiredManager(models.Manager):
    def get_query_set(self):
        return super(MaleManager, self).get_query_set().filter(age__gte = 60)

Queryset Manager, aller plus haut !

Pratique hein ? mais pas toujours .. Imaginer que par recoupement multiple, queryset croisés... "si si au bout d'un moment ça arrive", je récupére une liste de 30 personnes, et que parmi elles je souhaite extraire mes fameux retraités de sexe féminins, soyons fous.. J'aimerais beaucoup pouvoir écrire some_people.get_women().get_retired() ou some_people.get_retired().get_women(). Bref chainer mes filtres.

Remarque : some_people doit évidemment être un queryset de "Person"

Le code

Dans models.py :

class QuerySetManager(models.Manager):
    def get_query_set(self):
        return self.model.QuerySet(self.model)
    def __getattr__(self, attr, *args):
        return getattr(self.get_query_set(), attr, *args)
class Person(models.Model):
 ..... tout le blabla précédent ....
objects = QuerySetManager()
..............................................
    class QuerySet(QuerySet):
        def get_retired(self):
            return self.objects.filter(age_gte = 60)
        def get_women(self):
            return self.objects.filter(sex='F')

Voila vous savez tout...