Magazine Internet

Django - Dénormalisation d'un queryset

Publié le 24 novembre 2011 par Samuel Martin

Dans quelques rares cas, l'ORM de Django ne suffit plus. Lorsque votre requête est spécifique il existe plusieurs solutions que j'expose dans cet article illustré par le tri de liste.

Je reprends ici l'exemple de la dénormalisation. Dans le cas présent nous souhaitons récupérer une liste de critères triée par numéro (1, 2, 3). Si la vie était bien faite, un simple order_by sur l'attribut "numero" suffirait. Oui à condition que ce dernier soit un "integer" dans la base de données. Malheureusement l'attribut est un "CharField" / " Champ texte" et il est strictement interdit de corriger le type de champs (on stocke également des éléments de la formes IMA-2).

Deux étapes importantes :

  1. Convertir l'attribut "CharField" en attribut "Integer" sur demande
  2. Créer la méthode de tri

Convertir l'attribut en entier

Le numéro est stocké dans l'attribut "num" de notre modèle, nous souhaiterons le transformer en entier si c'est possible.

    def get_num_in_integer(self):
        try:
             return int(self.num)
        except ValueError:
            return self.num

Trier / dénormaliser

criteria = sorted(criteria, key=lambda a: a.get_num_in_integer())

Petite ligne magique permettant de trier une liste de critère en fonction de son numéro, converti en entier à la volée

Prudence

Très bien, mais garder bien à l'esprit que la dénormalisation est à effectuer en cas de force majeure et surtout à la fin de vos vues, juste avant de passer le bébé au template.

Un queryset est une liste mais une liste n'est pas un queryset : Une fois passé dans la moulinette du "sorted" aucune méthode de queryset n'est disponible ! ce n'est plus un queryset mais une liste.. c'est compris ?

Utiliser une méthode de queryset sur une liste

Le titre est exagéré, il est préférable de dire "créer une méthode de liste".

Comment faire ?

IRC python-fr (flupke je crois) me répond  Il faut sous classer mon ami 
class MyList(list):
    __slots__ = () #optimisation ah oui ?

    def count(self):
        return len(self)
criteria = MyList(criteria)

Et voila côté template je peux ainsi utiliser aveuglement "criteria.count" comme si je manipulais un queryset.


Retour à La Une de Logo Paperblog

A propos de l’auteur


Samuel Martin 21 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte

Dossiers Paperblog

Magazine