{"title":"Traitement conditionnel de vue","version":"1.9","locale":"fr","docname":"topics/conditional-view-processing","url":"/fr/1.9/topics/conditional-view-processing/","canonical":"https://djangodocs.dev/fr/1.9/topics/conditional-view-processing/","summary":"Les clients HTTP peuvent envoyer plusieurs en-têtes pour signaler au serveur des copies de ressources qu’ils ont déjà rencontrées.","html":"<h1>Traitement conditionnel de vue<a class=\"heading-anchor\" href=\"#conditional-view-processing\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Les clients HTTP peuvent envoyer plusieurs en-têtes pour signaler au serveur des copies de ressources qu’ils ont déjà rencontrées. C’est fréquemment employé lors de l’obtention d’une page Web (par une requête HTTP <code class=\"docutils literal notranslate\">GET</code>) pour éviter d’envoyer toutes les données quand le client en a déjà récupéré une partie. Cependant, les mêmes en-têtes peuvent être utilisés par toutes les méthodes HTTP (<code class=\"docutils literal notranslate\">POST</code>, <code class=\"docutils literal notranslate\">PUT</code>, <code class=\"docutils literal notranslate\">DELETE</code>, etc.).</p>\n<p>Pour chaque page (réponse) que Django renvoie depuis une vue, il est susceptible de définir deux en-têtes HTTP : l’en-tête <code class=\"docutils literal notranslate\">ETag</code> et l’en-tête <code class=\"docutils literal notranslate\">Last-Modified</code>. Ces en-têtes sont facultatifs dans les réponses HTTP. Ils peuvent être définis par la fonction de vue ou il est possible de compter sur l’intergiciel <a class=\"reference internal\" href=\"/fr/1.9/ref/middleware/#django.middleware.common.CommonMiddleware\" title=\"django.middleware.common.CommonMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">CommonMiddleware</code></a> pour définir l’en-tête <code class=\"docutils literal notranslate\">ETag</code>.</p>\n<p>Lorsqu’un client demande une nouvelle fois la même ressource, il peut envoyer avec la requête un en-tête tel que <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-3.3\">If-modified-since</a> ou <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-3.4\">If-unmodified-since</a> contenant la date de dernière modification qu’il a reçue, ou <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-3.1\">If-match</a> ou <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-3.2\">If-none-match</a> contenant la dernière valeur <code class=\"docutils literal notranslate\">ETag</code> qu’il a reçue. Si la version actuelle de la page correspond à la valeur <code class=\"docutils literal notranslate\">ETag</code> envoyée par le client ou que la ressource n’a pas été modifiée entre temps, le serveur peut renvoyer un code de statut 304 au lieu d’une réponse complète, indiquant par là au client que rien n’a changé. En fonction de l’en-tête, si la page a été modifiée ou ne correspond pas au contenu <code class=\"docutils literal notranslate\">ETag</code> envoyé par le client, un code de statut 412 (Precondition Failed) peut être renvoyé.</p>\n<p>Dans les cas où vous avez besoin d’un contrôle plus fin, vous pouvez utiliser les fonctions de traitement conditionnel par vue.</p>\n<aside class=\"version-note version-changed\" data-version=\"1.8\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 1.8</p><p>La prise en charge de l’en-tête <code class=\"docutils literal notranslate\">If-unmodified-since</code> a été ajoutée au traitement de vue conditionnel.</p>\n</aside>\n<section id=\"the-condition-decorator\">\n<span id=\"conditional-decorators\"></span><h2>Le décorateur <code class=\"docutils literal notranslate\">condition</code><a class=\"heading-anchor\" href=\"#the-condition-decorator\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Parfois (et assez souvent en réalité), vous pouvez créer des fonctions pour calculer rapidement la valeur <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-2.3\">ETag</a> ou la date de dernière modification d’une ressource, <strong>sans</strong> devoir procéder à toutes les opérations nécessaires à la construction complète de la vue. Django peut ensuite utiliser ces fonctions pour fournir une option de « court-circuitage rapide » du traitement de la vue. Par exemple pour indiquer au client que le contenu n’a pas été modifié depuis la requête précédente.</p>\n<p>These two functions are passed as parameters to the\n<code class=\"docutils literal notranslate\">django.views.decorators.http.condition</code> decorator. This decorator uses\nthe two functions (you only need to supply one, if you can’t compute both\nquantities easily and quickly) to work out if the headers in the HTTP request\nmatch those on the resource. If they don’t match, a new copy of the resource\nmust be computed and your normal view is called.</p>\n<p>La signature du décorateur <code class=\"docutils literal notranslate\">condition</code> correspond à ceci :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>condition<span class=\"p\">(</span>etag_func<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> last_modified_func<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Les deux fonctions, celle pour calculer la valeur <code class=\"docutils literal notranslate\">ETag</code> et celle pour la date de dernière modification, reçoivent l’objet <code class=\"docutils literal notranslate\">request</code> entrant ainsi que les mêmes paramètres, dans le même ordre, que la fonction de vue qu’elles enveloppent. La fonction de rappel <code class=\"docutils literal notranslate\">last_modified_func</code> doit renvoyer une valeur date/heure standard indiquant la date de dernière modification de la ressource ou <code class=\"docutils literal notranslate\">None</code> si la ressource n’existe pas. La fonction de rappel du décorateur <code class=\"docutils literal notranslate\">etag</code> doit renvoyer une chaîne représentant la valeur <a class=\"reference external\" href=\"https://tools.ietf.org/html/rfc7232#section-2.3\">Etag</a> de la ressource, ou <code class=\"docutils literal notranslate\">None</code> si la ressource n’existe pas.</p>\n<p>Il est probablement plus adéquat d’expliquer la façon d’utiliser cette fonctionnalité par un exemple. Admettons que vous ayez ces deux modèles représentant un système simple de blog :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n<span class=\"k\">class</span> <span class=\"nc\">Blog</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">Entry</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    blog <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>Blog<span class=\"p\">)</span>\n    published <span class=\"o\">=</span> models<span class=\"o\">.</span>DateTimeField<span class=\"p\">(</span>default<span class=\"o\">=</span>datetime<span class=\"o\">.</span>datetime<span class=\"o\">.</span>now<span class=\"p\">)</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>Si la page d’accueil affichant les derniers articles de blog ne change que lorsque vous ajoutez un nouvel article, vous pouvez calculer très rapidement la date de dernière modification. Vous avez besoin de la date <code class=\"docutils literal notranslate\">published</code> la plus récente de chaque article associé à ce blog. Une façon de le faire serait :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">latest_entry</span><span class=\"p\">(</span>request<span class=\"p\">,</span> blog_id<span class=\"p\">):</span>\n    <span class=\"k\">return</span> Entry<span class=\"o\">.</span>objects<span class=\"o\">.</span>filter<span class=\"p\">(</span>blog<span class=\"o\">=</span>blog_id<span class=\"p\">)</span><span class=\"o\">.</span>latest<span class=\"p\">(</span><span class=\"s2\">&quot;published&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span>published\n</code></pre></div>\n<p>Vous pouvez dès lors utiliser cette fonction pour fournir une détection rapide d’une page d’accueil inchangée :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.views.decorators.http</span> <span class=\"kn\">import</span> condition\n\n<span class=\"nd\">@condition</span><span class=\"p\">(</span>last_modified_func<span class=\"o\">=</span>latest_entry<span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">front_page</span><span class=\"p\">(</span>request<span class=\"p\">,</span> blog_id<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n</section>\n<section id=\"shortcuts-for-only-computing-one-value\">\n<h2>Raccourcis pour le calcul d’une seule valeur<a class=\"heading-anchor\" href=\"#shortcuts-for-only-computing-one-value\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>En règle générale, si vous pouvez fournir des fonctions à la fois pour le calcul de la valeur <code class=\"docutils literal notranslate\">ETag</code> et la date de dernière modification, il est bien de le faire. On ne connaît pas à l’avance les en-têtes qu’un client HTTP donné va envoyer, on peut donc s’attendre à devoir gérer les deux cas de figure. Cependant, il peut arriver qu’une seule des deux valeurs soit facile à calculer et Django fournit donc des décorateurs qui ne gèrent que la valeur <code class=\"docutils literal notranslate\">ETag</code> ou que la date de dernière modification.</p>\n<p>Les décorateurs <code class=\"docutils literal notranslate\">django.views.decorators.http.etag</code> et <code class=\"docutils literal notranslate\">django.views.decorators.http.last_modified</code> reçoivent le même type de fonction que le décorateur <code class=\"docutils literal notranslate\">condition</code>. Leur signature est :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>etag<span class=\"p\">(</span>etag_func<span class=\"p\">)</span>\nlast_modified<span class=\"p\">(</span>last_modified_func<span class=\"p\">)</span>\n</code></pre></div>\n<p>Nous pourrions écrire l’exemple précédent qui n’utilisait que la fonction de dernière modification en choisissant l’un de ces décorateurs :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"nd\">@last_modified</span><span class=\"p\">(</span>latest_entry<span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">front_page</span><span class=\"p\">(</span>request<span class=\"p\">,</span> blog_id<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>…ou :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">front_page</span><span class=\"p\">(</span>request<span class=\"p\">,</span> blog_id<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\nfront_page <span class=\"o\">=</span> last_modified<span class=\"p\">(</span>latest_entry<span class=\"p\">)(</span>front_page<span class=\"p\">)</span>\n</code></pre></div>\n<section id=\"use-condition-when-testing-both-conditions\">\n<h3>Test des deux conditions avec <code class=\"docutils literal notranslate\">condition</code><a class=\"heading-anchor\" href=\"#use-condition-when-testing-both-conditions\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Il pourrait paraître plus élégant pour certaines personnes d’essayer d’enchaîner les décorateurs <code class=\"docutils literal notranslate\">etag</code> et <code class=\"docutils literal notranslate\">last_modified</code> pour tester les deux pré-conditions. Cependant, l’effet produit serait faux.</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"c1\"># Bad code. Don&#39;t do this!</span>\n<span class=\"nd\">@etag</span><span class=\"p\">(</span>etag_func<span class=\"p\">)</span>\n<span class=\"nd\">@last_modified</span><span class=\"p\">(</span>last_modified_func<span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"c1\"># ...</span>\n\n<span class=\"c1\"># End of bad code.</span>\n</code></pre></div>\n<p>Le premier décorateur n’a aucune conscience du second et pourrait répondre que la réponse n’a pas été modifiée même quand le second décorateur en déciderait autrement. Le décorateur <code class=\"docutils literal notranslate\">condition</code> utilise les deux fonctions de rappel de concert pour prendre la bonne décision.</p>\n</section>\n</section>\n<section id=\"using-the-decorators-with-other-http-methods\">\n<h2>Utilisation des décorateurs avec d’autres méthodes HTTP<a class=\"heading-anchor\" href=\"#using-the-decorators-with-other-http-methods\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Le décorateur <code class=\"docutils literal notranslate\">condition</code> est utile au-delà des requêtes <code class=\"docutils literal notranslate\">GET</code> et <code class=\"docutils literal notranslate\">HEAD</code> (les requêtes <code class=\"docutils literal notranslate\">HEAD</code> sont similaires aux requêtes <code class=\"docutils literal notranslate\">GET</code> dans cette optique). Il peut aussi être utilisé pour faire les vérifications nécessaires pour les requêtes <code class=\"docutils literal notranslate\">POST</code>, <code class=\"docutils literal notranslate\">PUT</code> et <code class=\"docutils literal notranslate\">DELETE</code>. Dans ces cas de figure, l’idée n’est pas de renvoyer une réponse « non modifiée », mais d’indiquer au client que la ressource qu’ils tentent de modifier a subi des modifications dans l’intervalle.</p>\n<p>Par exemple, considérez l’échange suivant entre un client et un serveur :</p>\n<ol class=\"arabic simple\">\n<li><p>Le client demande <code class=\"docutils literal notranslate\">/foo/</code>.</p></li>\n<li><p>Le serveur répond avec un contenu dont la valeur <code class=\"docutils literal notranslate\">ETag</code> vaut <code class=\"docutils literal notranslate\">&quot;abcd1234&quot;</code>.</p></li>\n<li><p>Le client envoie une requête HTTP <code class=\"docutils literal notranslate\">PUT</code> vers <code class=\"docutils literal notranslate\">/foo/</code> pour mettre à jour la ressource. Il envoie également un en-tête <code class=\"docutils literal notranslate\">If-Match: &quot;abcd1234&quot;</code> pour indiquer la version qu’il tente de mettre à jour.</p></li>\n<li><p>Server checks to see if the resource has changed, by computing the ETag\nthe same way it does for a <code class=\"docutils literal notranslate\">GET</code> request (using the same function).\nIf the resource <em>has</em> changed, it will return a 412 status code,\nmeaning « precondition failed ».</p></li>\n<li><p>Le client envoie une requête <code class=\"docutils literal notranslate\">GET</code> vers <code class=\"docutils literal notranslate\">/foo/</code> après la réception de la réponse 412 afin de récupérer une version mise à jour du contenu avant de le mettre à jour.</p></li>\n</ol>\n<p>La chose importante démontrée par cet exemple est que les mêmes fonctions peuvent être utilisées pour calculer les valeurs <code class=\"docutils literal notranslate\">ETag</code> et date de dernière modification dans toutes les situations. En fait, vous <strong>devez</strong> utiliser les mêmes fonctions afin que les mêmes valeurs soient renvoyées à chaque fois.</p>\n</section>\n<section id=\"comparison-with-middleware-conditional-processing\">\n<h2>Comparaison avec l’intergiciel de traitement conditionnel<a class=\"heading-anchor\" href=\"#comparison-with-middleware-conditional-processing\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Vous pouvez constater que Django fournit déjà une gestion conditionnelle de <code class=\"docutils literal notranslate\">GET</code> simple et directe via les intergiciels <a class=\"reference internal\" href=\"/fr/1.9/ref/middleware/#django.middleware.http.ConditionalGetMiddleware\" title=\"django.middleware.http.ConditionalGetMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">django.middleware.http.ConditionalGetMiddleware</code></a> et <a class=\"reference internal\" href=\"/fr/1.9/ref/middleware/#django.middleware.common.CommonMiddleware\" title=\"django.middleware.common.CommonMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">CommonMiddleware</code></a>. Bien qu’elles soient certainement simple d’utilisation et adaptées à de nombreuses situations, les fonctionnalités de ces intergiciels présentent des limites quant à un usage avancé :</p>\n<ul class=\"simple\">\n<li><p>Elles sont appliquées globalement à toutes les vues d’un projet.</p></li>\n<li><p>Elles ne vous économisent pas le travail de génération de la réponse elle-même, ce qui peut être coûteux.</p></li>\n<li><p>Elles ne sont adaptées qu’aux requêtes HTTP <code class=\"docutils literal notranslate\">GET</code>.</p></li>\n</ul>\n<p>Vous devriez choisir ici l’outil le plus approprié à votre problème particulier. Si vous arrivez à calculer rapidement les valeurs <code class=\"docutils literal notranslate\">ETag</code> et de date de dernière modification et que certaines vues prennent du temps à produire leur contenu, vous devriez envisager d’utiliser le décorateur <code class=\"docutils literal notranslate\">condition</code> présenté dans ce document. Par contre, si tout fonctionne déjà de manière assez fluide, restez-en à la solution des intergiciels et vous continuerez de réduire la quantité de trafic réseau en direction des clients dans les cas où les contenus des vues n’ont pas changé.</p>\n</section>","rootId":"conditional-view-processing","toc":[{"title":"Le décorateur condition","anchor":"the-condition-decorator","children":[]},{"title":"Raccourcis pour le calcul d’une seule valeur","anchor":"shortcuts-for-only-computing-one-value","children":[{"title":"Test des deux conditions avec condition","anchor":"use-condition-when-testing-both-conditions","children":[]}]},{"title":"Utilisation des décorateurs avec d’autres méthodes HTTP","anchor":"using-the-decorators-with-other-http-methods","children":[]},{"title":"Comparaison avec l’intergiciel de traitement conditionnel","anchor":"comparison-with-middleware-conditional-processing","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"Utilisation de Django","url":"/fr/1.9/topics/"}],"prev":{"docname":"topics/cache","title":"L’infrastructure de cache dans Django","url":"/fr/1.9/topics/cache/"},"next":{"docname":"topics/signing","title":"Signatures cryptographiques","url":"/fr/1.9/topics/signing/"},"formats":{"html":"/fr/1.9/topics/conditional-view-processing/","markdown":"/fr/1.9/topics/conditional-view-processing.md","json":"/fr/1.9/topics/conditional-view-processing.json"},"source":"https://github.com/django/django/blob/stable/1.9.x/docs/topics/conditional-view-processing.txt","official":"https://docs.djangoproject.com/fr/1.9/topics/conditional-view-processing/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","fr","ja","id","pt-br","es"]}