{"id":539,"date":"2010-04-02T11:40:36","date_gmt":"2010-04-02T09:40:36","guid":{"rendered":"http:\/\/j-mad.com\/blog\/?p=539"},"modified":"2010-04-02T11:40:36","modified_gmt":"2010-04-02T09:40:36","slug":"petits-tours-des-methodes-des-querysets","status":"publish","type":"post","link":"https:\/\/j-mad.com\/blog\/2010\/04\/02\/petits-tours-des-methodes-des-querysets\/","title":{"rendered":"Petits tours des m\u00e9thodes des querysets."},"content":{"rendered":"<p>Les queryset sont une des composantes importantes de Django. Comment en effet interagir avec la BD sans eux ?<\/p>\n<p>Mais est ce que cet outil si important et si souvent utilis\u00e9 est si bien connu que \u00e7a ?<\/p>\n<p>Parce que tout le monde connait count(), filter(), all() et exclude(). Mais qu&#8217;n est-il des autres m\u00e9thodes ? Perso, je suis le premier \u00e0 aller dans la doc, pour rev\u00e9rifier si ce que je voudrais n&#8217;existe pas d\u00e9j\u00e0&#8230;<\/p>\n<p>C&#8217;est le pourquoi de ce billet, lister quelques m\u00e9thodes &#8216;\u00e0 conna\u00eetre&#8217; des querysets (et puis comme \u00e7a la prochaine fois que j&#8217;aurais besoin de v\u00e9rifier un truc, je pourrais le faire en lisant du fran\u00e7ais et pas de l&#8217;anglais). (Ce n&#8217;est au final qu&#8217;une redite de la page de doc qui va bien, mais \u00e7a peut servir).<\/p>\n<h1>1- Les m\u00e9thodes qui renvoient un queryset (ou assimil\u00e9s)<\/h1>\n<h2>annotate(*args, **kwargs)<\/h2>\n<p>une petite m\u00e9thode bien pratique, qui permet de rajouter des colonnes calcul\u00e9es (en utilisant les classes d&#8217;agr\u00e9gat Sum,Count, etc d\u00e9fini par django) pour chaque objets r\u00e9cup\u00e9r\u00e9s dans le queryset.<\/p>\n<p>Et \u00e7a, c&#8217;est plut\u00f4t fort. Surtout que l&#8217;on peut, bien entendu, &#8216;traverser&#8217; les foreign key<br \/>\nL&#8217;un des exemples de la doc, montre cela en calculant pour un magasin le prix minimum et maximum des livres en vente :<\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:435px;\"><div class=\"python codecolorer\">Store.<span class=\"me1\">objects<\/span>.<span class=\"me1\">annotate<\/span><span class=\"br0\">&#40;<\/span>min_price<span class=\"sy0\">=<\/span>Min<span class=\"br0\">&#40;<\/span><span class=\"st0\">'books__price'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> max_price<span class=\"sy0\">=<\/span>Max<span class=\"br0\">&#40;<\/span><span class=\"st0\">'books__price'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><\/div><\/div>\n<h2>values(*fields) et Values_list (*fields)<\/h2>\n<p>Deux m\u00e9thodes plus que miam.<br \/>\nValues retourne un ValuesQuerySet qui est en fait un queryset compos\u00e9 d&#8217;une liste de dictionnaires au lieu d&#8217;une liste d&#8217;instance d&#8217;objet mod\u00e8le. Chaque dictionnaire repr\u00e9sente un objet, les paire cl\u00e9s \/ valeur repr\u00e9sentant le nom de l&#8217;attribut (la key) et la valeur de l&#8217;attribut (sa valeur).<br \/>\nOn peut passer \u00e0 values un param\u00e8tre optionnel *fields, qui permet de sp\u00e9cifier la liste des noms d&#8217;attribut (des strings donc) que l&#8217;on veut r\u00e9cup\u00e9rer.<br \/>\nExemple :<\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:435px;\"><div class=\"python codecolorer\"><span class=\"sy0\">&gt;&gt;&gt;<\/span>Blog.<span class=\"me1\">objects<\/span>.<span class=\"me1\">values<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#91;<\/span><span class=\"br0\">&#123;<\/span><span class=\"st0\">'id'<\/span>: <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'name'<\/span>: <span class=\"st0\">'Beatles Blog'<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'tagline'<\/span>: <span class=\"st0\">'All the latest Beatles news.'<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"sy0\">&gt;&gt;&gt;<\/span> Blog.<span class=\"me1\">objects<\/span>.<span class=\"me1\">values<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'id'<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'name'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#91;<\/span><span class=\"br0\">&#123;<\/span><span class=\"st0\">'id'<\/span>: <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'name'<\/span>: <span class=\"st0\">'Beatles Blog'<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#93;<\/span><\/div><\/div>\n<p>Deux choses importantes \u00e0 se rappeler, values ne r\u00e9cup\u00e8re rien pour les manytomany et dans le cas des FK, la cl\u00e9 du dico est le nom &#8216;vrai&#8217; de l&#8217;attribut dans la table (souvent avec _id donc) et la valeur, la valeur de la PK de la FK. Et comme le voit dans l&#8217;exemple, si on veut passer le nom explicite de l&#8217;attribut de la fk, on peut au choix mettre ou pas le _id, le r\u00e9sultat est le m\u00eame.<\/p>\n<p>Exemple :<\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:435px;\"><div class=\"python codecolorer\"><span class=\"sy0\">&gt;&gt;&gt;<\/span> Entry.<span class=\"me1\">objects<\/span>.<span class=\"me1\">values<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#91;<\/span><span class=\"br0\">&#123;<\/span><span class=\"st0\">'blog_id: 1, '<\/span>headline<span class=\"st0\">': u'<\/span>First Entry<span class=\"st0\">', ...}, ...]<br \/>\n<br \/>\n&gt;&gt;&gt; Entry.objects.values('<\/span>blog<span class=\"st0\">')<br \/>\n[{'<\/span>blog<span class=\"st0\">': 1}, ...]<br \/>\n<br \/>\n&gt;&gt;&gt; Entry.objects.values('<\/span>blog_id<span class=\"st0\">')<br \/>\n[{'<\/span>blog_id<span class=\"st0\">': 1}, ...]<\/span><\/div><\/div>\n<p>values_list c&#8217;est \u00e0 peu pr\u00e8s la m\u00eame chose que values, sauf que c&#8217;est une liste de tuple et pas une liste de dico. On peut en plus lui passer un param\u00eatre flat que l&#8217;on peut mettre \u00e0 true , pour &#8216;aplatir&#8217; les tuples quand l&#8217;on demande qu&#8217;un seul champ (juste coolos quand on veut une liste de pk)<\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:435px;\"><div class=\"python codecolorer\"><span class=\"sy0\">&gt;&gt;&gt;<\/span> Entry.<span class=\"me1\">objects<\/span>.<span class=\"me1\">values_list<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'id'<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">order_by<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'id'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#91;<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span><span class=\"nu0\">3<\/span><span class=\"sy0\">,<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> ...<span class=\"br0\">&#93;<\/span><br \/>\n<br \/>\n<span class=\"sy0\">&gt;&gt;&gt;<\/span> Entry.<span class=\"me1\">objects<\/span>.<span class=\"me1\">values_list<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'id'<\/span><span class=\"sy0\">,<\/span> flat<span class=\"sy0\">=<\/span><span class=\"kw2\">True<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">order_by<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'id'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#91;<\/span><span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">3<\/span><span class=\"sy0\">,<\/span> ...<span class=\"br0\">&#93;<\/span><\/div><\/div>\n<h3>A quoi sert values et values_list ?<\/h3>\n<p>L&#8217;int\u00e9r\u00eat c&#8217;est qu&#8217;un ValuesQuerySet, c&#8217;est comme un queryset. Et que donc on peut utiliser toutes les m\u00e9thodes des queryset dessus. Y compris refiltrer, order_by, etc etc ..<\/p>\n<p>Et que dans le m\u00eame temps, on peut all\u00e9ger la charge, surtout si on a des gros models dont l&#8217;on ne veut utiliser que quelques champs.<\/p>\n<h2>defer (*fields)<\/h2>\n<p>Permet d&#8217;indiquer au queryset de ne pas r\u00e9cup\u00e9rer automatiquement le contenu des champs qui sont pass\u00e9s en param\u00eatre du defer. Ca peut \u00eatre utile dans le cas de gros champ texte par exemple (imaginons une vue en liste de billet de blog o\u00f9 l&#8217;on ne veut que les titres des billets et pas leur contenu, utiliser un defer(&#8216;body&#8217;) pourrait \u00eatre une possibilit\u00e9 , utiliser un values en serait une autre)<\/p>\n<p>les champs deferred seront r\u00e9cup\u00e9r\u00e9s quand on les appelera explicitement. Pour annuler les defer d&#8217;un queryset, il suffit d&#8217;appeler la fonction avec None en param\u00eatre.<\/p>\n<h2>only (*fields)<\/h2>\n<p>C&#8217;est l&#8217;inverse du defer, on ne r\u00e9cup\u00e8re que certains champs.<\/p>\n<h1>2- Les fonctions qui ne renvoient pas un queryset.<\/h1>\n<h2>in_bulk(id_list)<\/h2>\n<p>Cette petite fonction bien sympa prend une liste de pk et renvoie un dico des objets qui correspondent (les cl\u00e9s \u00e9tant les pk)<\/p>\n<h2>latest(field_name=None)<\/h2>\n<p>Renvoie le dernier objet, ins\u00e9r\u00e9 dans la base, en se basant sur les dates et en utilisant le champ pass\u00e9 en param\u00e8tre (qui doit donc \u00eatre un champ\u00a0 date).<br \/>\nSi le model en question d\u00e9finit la Meta get_latest_by, on peut appeler latest sans argument.<\/p>\n<p>Ok, cette fonction &#8216;ne sert \u00e0 rien&#8217; \u00e0 part pour rendre plus lisible le code. Mais bon, \u00e7a ne mange pas de pain. Et l&#8217;utilisation de la Meta get_latest_by permet de &#8216;centraliser&#8217; la fa\u00e7on de rechercher le dernier, ce qui rendra une modification plus facile.<\/p>\n<h2>aggregate(*args, **kwargs)<\/h2>\n<p>Retourne un dico des valeurs d&#8217;aggr\u00e9gat calcul\u00e9s non pas objet par objet comme avec annotate, mais sur tout le queryset.<\/p>\n<p>A vous les sommes de champ, les moyennes ou autre. Vive les rapports :).<\/p>\n<div class=\"codecolorer-container python default\" style=\"overflow:auto;white-space:nowrap;width:435px;\"><div class=\"python codecolorer\"><span class=\"sy0\">&gt;&gt;&gt;<\/span> q <span class=\"sy0\">=<\/span> Blog.<span class=\"me1\">objects<\/span>.<span class=\"me1\">aggregate<\/span><span class=\"br0\">&#40;<\/span>Count<span class=\"br0\">&#40;<\/span><span class=\"st0\">'entry'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><span class=\"st0\">'entry__count'<\/span>: <span class=\"nu0\">16<\/span><span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"sy0\">&gt;&gt;&gt;<\/span> q <span class=\"sy0\">=<\/span> Blog.<span class=\"me1\">objects<\/span>.<span class=\"me1\">aggregate<\/span><span class=\"br0\">&#40;<\/span>number_of_entries<span class=\"sy0\">=<\/span>Count<span class=\"br0\">&#40;<\/span><span class=\"st0\">'entry'<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#123;<\/span><span class=\"st0\">'number_of_entries'<\/span>: <span class=\"nu0\">16<\/span><span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>et comme pour annotate, on peut contr\u00f4ler le nom, ici de la cl\u00e9, que notre valeur calcul\u00e9e.<\/p>\n<h2>exists()<\/h2>\n<p>cette fonction n&#8217;existe pas encore dans django, elle sera pr\u00e9sente dans la 1.2. Elle permet tout simplement de savoir si le queryset est vide ou pas. (oui je sais, devoir attendre la 1.2 pour avoir cette fonction.. mais bon \ud83d\ude42 ).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Les queryset sont une des composantes importantes de Django. Comment en effet interagir avec la BD sans eux ? Mais est ce que cet outil si important et si souvent utilis\u00e9 est si bien connu que \u00e7a ? Parce que tout le monde connait count(), filter(), all() et exclude(). Mais qu&#8217;n est-il des autres m\u00e9thodes &hellip; <a href=\"https:\/\/j-mad.com\/blog\/2010\/04\/02\/petits-tours-des-methodes-des-querysets\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Petits tours des m\u00e9thodes des querysets.<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[6],"tags":[99,98],"class_list":["post-539","post","type-post","status-publish","format-standard","hentry","category-django","tag-django","tag-python"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p12cdp-8H","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/posts\/539","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/comments?post=539"}],"version-history":[{"count":2,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/posts\/539\/revisions"}],"predecessor-version":[{"id":541,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/posts\/539\/revisions\/541"}],"wp:attachment":[{"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/media?parent=539"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/categories?post=539"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/j-mad.com\/blog\/wp-json\/wp\/v2\/tags?post=539"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}