{"title":"Écriture d’expressions de requêtes personnalisées","version":"5.1","locale":"fr","docname":"howto/custom-lookups","url":"/fr/5.1/howto/custom-lookups/","canonical":"https://djangodocs.dev/fr/5.1/howto/custom-lookups/","summary":"Django offre une large variété d’ expressions de recherche intégrées pour filtrer les requêtes (par exemple, exact et icontains ). Cette documentation explique…","html":"<h1>Écriture d’expressions de requêtes personnalisées<a class=\"heading-anchor\" href=\"#how-to-write-custom-lookups\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django offre une large variété d’<a class=\"reference internal\" href=\"/fr/5.1/ref/models/querysets/#field-lookups\"><span class=\"std std-ref\">expressions de recherche intégrées</span></a> pour filtrer les requêtes (par exemple, <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">icontains</span></code>). Cette documentation explique comment écrire des expressions personnalisées et comment modifier le comportement d’expressions existantes. Pour la référence des API de recherche, consultez <a class=\"reference internal\" href=\"/fr/5.1/ref/models/lookups/\"><span class=\"doc\">API de référence des expressions de recherche</span></a>.</p>\n<section id=\"a-lookup-example\">\n<h2>Un exemple d’expression de recherche<a class=\"heading-anchor\" href=\"#a-lookup-example\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Commençons par une petite expression de recherche. Nous allons écrire une expression personnalisée <code class=\"docutils literal notranslate\"><span class=\"pre\">ne</span></code> fonctionnant à l’inverse de <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code>. <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code> s’exprime comme ceci en SQL :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"ss\">&quot;author&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;name&quot;</span><span class=\"w\"> </span><span class=\"o\">&lt;&gt;</span><span class=\"w\"> </span><span class=\"s1\">&#39;Jack&#39;</span>\n</code></pre></div>\n<p>Ce code SQL est indépendant de la base de données, nous n’avons donc pas à nous soucier de la gestion de bases de données différentes.</p>\n<p>Deux étapes sont nécessaires pour que cela fonctionne. Nous devons d’abord implémenter la recherche, puis nous devons informer Django de sa disponibilité</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Lookup</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">NotEqual</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ne&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_lhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> &lt;&gt; </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n</code></pre></div>\n<p>Pour inscrire la recherche <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code>, il faut appeler <code class=\"docutils literal notranslate\"><span class=\"pre\">register_lookup</span></code> sur la classe de champ pour lequel nous souhaitons rendre disponible cette recherche. Dans ce cas, l’expression peut s’appliquer à toutes les sous-classes de <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>, c’est pourquoi nous l’inscrivons directement dans <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>:</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\n\n<span class=\"n\">Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">NotEqual</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>L’enregistrement d’expression peut aussi se faire par la technique de décoration :</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\n\n\n<span class=\"nd\">@Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">NotEqualLookup</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>Nous pouvons dorénavant écrire <code class=\"docutils literal notranslate\"><span class=\"pre\">champ__ne</span></code> pour n’importe quel <code class=\"docutils literal notranslate\"><span class=\"pre\">champ</span></code>. Il faut s’assurer que l’inscription a lieu avant la création de tout jeu de requête utilisant l’expression. Il est possible de placer cette implémentation dans un fichier <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code> ou d’enregistrer l’expression dans la méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">ready()</span></code> d’une classe <code class=\"docutils literal notranslate\"><span class=\"pre\">AppConfig</span></code>.</p>\n<p>En examinant plus précisément l’implémentation, le premier attribut obligatoire est <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>. Cela permet à l’ORM de savoir comment interpréter <code class=\"docutils literal notranslate\"><span class=\"pre\">name__ne</span></code> et d’utiliser <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> pour produire le code SQL. Par convention, ces noms sont toujours en minuscules et ne contiennent que des lettres, mais la seule exigence absolue est l’interdiction d’utiliser la chaîne <code class=\"docutils literal notranslate\"><span class=\"pre\">__</span></code>.</p>\n<p>Nous devons ensuite définir la méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Elle accepte un objet <code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code> appelé <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> ainsi que la connexion de base de données active. Les objets <code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code> ne sont pas documentés, mais la seule chose à savoir à leur sujet est qu’ils comportent une méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">compile()</span></code> qui renvoie un tuple contenant une chaîne SQL ainsi que les paramètres à insérer dans cette chaîne. Dans la plupart des cas, il n’est pas nécessaire de l’utiliser directement et il suffit alors de la transmettre à <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs()</span></code>.</p>\n<p>Un objet <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> fonctionne avec deux valeurs, <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></code>, qui signifient côté gauche (« left-hand side ») et côté droite (« right-hand side »). Le côté gauche est normalement une référence de champ, mais cela peut aussi être n’importe quel objet implémentant l’<a class=\"reference internal\" href=\"/fr/5.1/ref/models/lookups/#query-expression\"><span class=\"std std-ref\">API d’expression de recherche</span></a>. Le côté droit correspond à la valeur donnée par l’utilisateur. Dans l’exemple  <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code>, le côté gauche est une référence au champ <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> du modèle <code class=\"docutils literal notranslate\"><span class=\"pre\">Author</span></code>, alors que <code class=\"docutils literal notranslate\"><span class=\"pre\">'Jack'</span></code> correspond au côté droit.</p>\n<p>Nous appelons <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> pour les convertir en valeurs nécessaires pour le code SQL en utilisant l’objet <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> décrit précédemment. Ces méthodes renvoient des tuples contenant le code SQL ainsi que les paramètres à insérer dans ce code, exactement comme nous en avons besoin pour la valeur de retour de notre méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Dans l’exemple ci-dessus, <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> renvoie <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;author&quot;.&quot;name&quot;',</span> <span class=\"pre\">[])</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> renvoie <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;%s&quot;',</span> <span class=\"pre\">['Jack'])</span></code>. Dans cet exemple, le côté gauche ne contient aucun paramètre, mais cela dépend de l’objet concerné, il faut donc tout de même les inclure dans les paramètres que nous renvoyons.</p>\n<p>Pour terminer, nous combinons les différentes parties dans une expression SQL avec <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code>, et nous fournissons tous les paramètres pour la requête. Nous renvoyons ensuite un tuple contenant la chaîne SQL produite et ses paramètres.</p>\n</section>\n<section id=\"a-transformer-example\">\n<h2>Un exemple de transformateur<a class=\"heading-anchor\" href=\"#a-transformer-example\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>La recherche personnalisée ci-dessus va très bien, mais dans certains cas, il est souhaitable d’enchaîner des recherches les unes après les autres. Par exemple, supposons que nous construisons une application où nous souhaitons exploiter l’opérateur <code class=\"docutils literal notranslate\"><span class=\"pre\">abs()</span></code>. Nous avons un modèle <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment</span></code> qui enregistre une valeur de départ, une valeur de fin et la modification (début - fin). Nous aimerions trouver toutes les expériences où la modification est égale à une certaine valeur (<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code>), ou que la valeur ne dépasse pas un seuil limite (<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code>).</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Cet exemple est un peu tiré par les cheveux, mais il démontre bien l’étendue des fonctionnalités possibles de manière indépendante de la base de données, et sans dupliquer une fonctionnalité déjà présente dans Django.</p>\n</aside>\n<p>Nous allons commencer par écrire un transformateur <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>. Il va faire appel à la fonction SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS()</span></code> pour transformer la valeur avant la comparaison :</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ABS&quot;</span>\n</code></pre></div>\n<p>Ensuite, nous allons l’inscrire pour le champ <code class=\"docutils literal notranslate\"><span class=\"pre\">IntegerField</span></code>:</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">IntegerField</span>\n\n<span class=\"n\">IntegerField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">AbsoluteValue</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Nous pouvons maintenant exécuter les requêtes que nous avions en tête. <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code> générera le code SQL suivant :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>En utilisant <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> au lieu de <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>, cela signifie que nous avons la possibilité d’enchaîner d’autres recherches à la suite. Ainsi, <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> générera le code SQL suivant :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">&lt;</span><span class=\"w\"> </span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>Notez que dans le cas où aucune autre recherche n’a été ajoutée, Django interprète <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs=27</span></code> comme <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__exact=27</span></code>.</p>\n<p>Cela permet aussi d’utiliser le résultat dans les clauses <code class=\"docutils literal notranslate\"><span class=\"pre\">ORDER</span> <span class=\"pre\">BY</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">DISTINCT</span> <span class=\"pre\">ON</span></code>. Par exemple, <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.order_by('change__abs')</span></code> produit :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">ORDER</span><span class=\"w\"> </span><span class=\"k\">BY</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"k\">ASC</span>\n</code></pre></div>\n<p>Et pour les bases de données qui prennent en charge l’instruction <code class=\"docutils literal notranslate\"><span class=\"pre\">DISTINCT</span></code> pour des champs spécifiques (comme PostgreSQL), <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.distinct('change__abs')</span></code> produit :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">DISTINCT</span><span class=\"w\"> </span><span class=\"k\">ON</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Lorsqu’il recherche quelles sont les expressions de recherche autorisées après l’application de <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>, Django se base sur l’attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code>. Nous n’avons pas eu besoin de le préciser ici car il n’a pas changé, mais si nous avions appliqué <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> à un champ représentant un type plus complexe (par exemple un point relatif à une origine ou un nombre complexe), nous aurions pu vouloir indiquer que la transformation renvoie un type <code class=\"docutils literal notranslate\"><span class=\"pre\">FloatField</span></code> dans l’optique de recherches subséquentes. Cela peut se faire en ajoutant un attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code> à la transformation :</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">FloatField</span><span class=\"p\">,</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ABS&quot;</span>\n\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">output_field</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">FloatField</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>Cela garantit que les recherches suivantes comme dans <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lte</span></code> se comportent comme elles le feraient avec un champ</p>\n</section>\n<section id=\"writing-an-efficient-abs-lt-lookup\">\n<h2>Écriture d’une recherche <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lt</span></code> efficace<a class=\"heading-anchor\" href=\"#writing-an-efficient-abs-lt-lookup\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Lors de l’utilisation de l’expression  <code class=\"docutils literal notranslate\"><span class=\"pre\">abs</span></code> écrite ci-dessus, le code SQL produit n’utilise pas les index de manière efficace dans certains cas. En particulier, quand on écrit <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__lt=27</span></code>, c’est équivalent à <code class=\"docutils literal notranslate\"><span class=\"pre\">change__gt=-27</span></code> AND <code class=\"docutils literal notranslate\"><span class=\"pre\">change__lt=27</span></code> (dans le cas de <code class=\"docutils literal notranslate\"><span class=\"pre\">lte</span></code>, nous pourrions utiliser l’expression SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">BETWEEN</span></code>).</p>\n<p>Nous aimerions donc que <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> produise le code SQL suivant :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">..</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"w\"> </span><span class=\"o\">&lt;</span><span class=\"w\"> </span><span class=\"mi\">27</span><span class=\"w\"> </span><span class=\"k\">AND</span><span class=\"w\"> </span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"w\"> </span><span class=\"o\">&gt;</span><span class=\"w\"> </span><span class=\"o\">-</span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>L’implémentation 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><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Lookup</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValueLessThan</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;lt&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"n\">compiler</span><span class=\"o\">.</span><span class=\"n\">compile</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lhs</span><span class=\"o\">.</span><span class=\"n\">lhs</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span> <span class=\"o\">+</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> &lt; </span><span class=\"si\">%s</span><span class=\"s2\"> AND </span><span class=\"si\">%s</span><span class=\"s2\"> &gt; -</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n\n\n<span class=\"n\">AbsoluteValue</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">AbsoluteValueLessThan</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Plusieurs éléments méritent d’être signalés. Tout d’abord, <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code> n’appelle pas <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code>. Au lieu de cela, il omet la transformation de <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> effectuée par <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> et utilise la variable <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> originale. C’est-à-dire que nous voulons obtenir <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;experiments&quot;.&quot;change&quot;</span></code> et non <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS(&quot;experiments&quot;.&quot;change&quot;)</span></code>. La référence directe à <code class=\"docutils literal notranslate\"><span class=\"pre\">self.lhs.lhs</span></code> est sûre car <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code> ne peut être accédée qu’au travers de l’expression <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>, ce qui veut dire que <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> est toujours une instance de <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>.</p>\n<p>Remarquez aussi que comme les deux côtés sont utilisés plusieurs fois dans la requête, les paramètres doivent contenir aussi plusieurs fois <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs_params</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs_params</span></code>.</p>\n<p>La requête finale procède à l’inversion (<code class=\"docutils literal notranslate\"><span class=\"pre\">27</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">-27</span></code>) directement dans la base de données. La raison de faire cela est que si <code class=\"docutils literal notranslate\"><span class=\"pre\">self.rhs</span></code> représente autre chose qu’une valeur entière simple (par exemple une référence <code class=\"docutils literal notranslate\"><span class=\"pre\">F()</span></code>), nous ne pouvons pas faire la transformation dans le code Python.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>En fait, la plupart des recherches avec <code class=\"docutils literal notranslate\"><span class=\"pre\">__abs</span></code> pourraient être implémentées comme des requêtes d’intervalle comme celle-ci, et pour la plupart des moteurs de base de données, il serait probablement plus judicieux de le faire afin de tirer parti au maximum des index. Cependant, avec PostgreSQL, il est possible d’ajouter un index sur <code class=\"docutils literal notranslate\"><span class=\"pre\">abs(change)</span></code> ce qui permettrait à ces requêtes d’être très efficaces.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>Un exemple de transformateur bilatéral<a class=\"heading-anchor\" href=\"#a-bilateral-transformer-example\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>L’exemple <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> que nous avons abordé précédemment est une transformation qui s’applique au côté gauche de l’expression. Il peut arriver que l’on veuille appliquer la transformation à la fois aux côtés gauche et droit de l’expression. Par exemple, si vous souhaitez filtrer une requête sur la base de l’égalité des côtés gauche et droit après leur avoir appliqué une fonction SQL quelconque.</p>\n<p>Examinons ici les transformations non sensibles à la casse. Cette transformation n’est pas très utile en réalité car Django contient déjà un certain nombre d’expressions de recherche non sensibles à la casse, mais cela fera une excellente démonstration des transformations bilatérales et neutres en terme de moteur de base de données.</p>\n<p>Nous définissons une transformation <code class=\"docutils literal notranslate\"><span class=\"pre\">UpperCase</span></code> qui utilise la fonction SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">UPPER()</span></code> pour transformer les valeurs avant leur comparaison. Nous définissons <a class=\"reference internal\" href=\"/fr/5.1/ref/models/lookups/#django.db.models.Transform.bilateral\" title=\"django.db.models.Transform.bilateral\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">bilateral</span> <span class=\"pre\">=</span> <span class=\"pre\">True</span></code></a> pour indiquer que cette transformation doit s’appliquer aux deux côtés <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></code>:</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">UpperCase</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;upper&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;UPPER&quot;</span>\n    <span class=\"n\">bilateral</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>Puis, occupons-nous de l’enregistrement :</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CharField</span><span class=\"p\">,</span> <span class=\"n\">TextField</span>\n\n<span class=\"n\">CharField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">UpperCase</span><span class=\"p\">)</span>\n<span class=\"n\">TextField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">UpperCase</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Dorénavant, la requête <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__upper=&quot;doe&quot;)</span></code> va produire une expression non sensible à la casse comme ceci :</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">UPPER</span><span class=\"p\">(</span><span class=\"ss\">&quot;author&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;name&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"k\">UPPER</span><span class=\"p\">(</span><span class=\"s1\">&#39;doe&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"writing-alternative-implementations-for-existing-lookups\">\n<h2>Écriture d’implémentations alternatives pour des recherches existantes<a class=\"heading-anchor\" href=\"#writing-alternative-implementations-for-existing-lookups\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Il peut arriver que le code SQL doive être différent d’une base de données à l’autre pour la même opération. Pour cet exemple, nous allons réécrire une implémentation personnalisée pour MySQL de l’opérateur NotEqual. Au lieu de <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code>, nous utiliserons l’opérateur <code class=\"docutils literal notranslate\"><span class=\"pre\">!=</span></code> (en réalité, presque toutes les bases de données acceptent les deux syntaxes, ce qui est le cas pour toutes les bases de données prises en charge officiellement par Django).</p>\n<p>Nous pouvons modifier le comportement pour un moteur spécifique en créant une sous-classe de <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> avec une méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">as_mysql</span></code>:</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\">class</span><span class=\"w\"> </span><span class=\"nc\">MySQLNotEqual</span><span class=\"p\">(</span><span class=\"n\">NotEqual</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_mysql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">extra_context</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_lhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> != </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n\n\n<span class=\"n\">Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">MySQLNotEqual</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Nous pouvons ensuite l’inscrire dans <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>. Elle prend la place de la classe <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> d’origine car elle possède le même attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>.</p>\n<p>Lors de la compilation d’une requête, Django cherche d’abord les méthodes <code class=\"docutils literal notranslate\"><span class=\"pre\">as_%s</span> <span class=\"pre\">%</span> <span class=\"pre\">connection.vendor</span></code> et se rabat ensuite sur <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Les noms « vendor » pour les moteurs intégrés sont <code class=\"docutils literal notranslate\"><span class=\"pre\">sqlite</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">postgresql</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">oracle</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">mysql</span></code>.</p>\n</section>\n<section id=\"how-django-determines-the-lookups-and-transforms-which-are-used\">\n<h2>Comment Django détermine les recherches et les transformations qui sont utilisées<a class=\"heading-anchor\" href=\"#how-django-determines-the-lookups-and-transforms-which-are-used\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Dans certains cas, il serait souhaitable de changer dynamiquement l’objet <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> ou <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> renvoyé en fonction du nom passé, plutôt que de le corriger. Par exemple, un champ pourrait stocker les coordonnées ou une dimension arbitraire, et vous souhaiteriez autoriser une syntaxe telle que <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(coords__x7=4)</span></code> pour renvoyer les objets où la 7ème coordonnée a la valeur 4. Pour cela, vous pourriez étendre <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup</span></code> avec quelque chose comme :</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\">class</span><span class=\"w\"> </span><span class=\"nc\">CoordinatesField</span><span class=\"p\">(</span><span class=\"n\">Field</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_lookup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">lookup_name</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">lookup_name</span><span class=\"o\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s2\">&quot;x&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">dimension</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">lookup_name</span><span class=\"o\">.</span><span class=\"n\">removeprefix</span><span class=\"p\">(</span><span class=\"s2\">&quot;x&quot;</span><span class=\"p\">))</span>\n            <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n                <span class=\"k\">pass</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">get_coordinate_lookup</span><span class=\"p\">(</span><span class=\"n\">dimension</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">get_lookup</span><span class=\"p\">(</span><span class=\"n\">lookup_name</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Vous pourriez ensuite définir <code class=\"docutils literal notranslate\"><span class=\"pre\">get_coordinate_lookup</span></code> de manière à ce qu’elle renvoie une sous-classe de <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> gérant la valeur applicable de <code class=\"docutils literal notranslate\"><span class=\"pre\">dimension</span></code>.</p>\n<p>Il existe une méthode similaire appelée <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code>. <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup()</span></code> doit toujours renvoyer une sous-classe de <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>, et <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code> une sous-classe de <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Il est important de se rappeler que les objets <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> peuvent ensuite être filtrés, alors que les objets <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> ne le peuvent pas.</p>\n<p>Lors du filtrage, s’il n’y a qu’un seul nom de recherche restant à résoudre, c’est un <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> qui est recherché. S’il y a plusieurs noms, la recherche visera un <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Dans la situation où il n’y a qu’un seul nom et qu’un `` Lookup`` n’est pas trouvé, un <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> est recherché, puis l’expression de recherche <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> est appliquée sur ce <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Toutes les séquences d’appels se terminent toujours par un <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. Pour clarifier :</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mylookup)</span></code> appelle <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup('mylookup')</span></code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mytransform__mylookup)</span></code> appelle <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code>, puis <code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup('mylookup')</span></code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mytransform)</span></code> appelle d’abord <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup('mytransform')</span></code> qui échouera, il appelle donc en dernier recours <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code> puis <code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup('exact')</span></code>.</p></li>\n</ul>\n</section>","rootId":"how-to-write-custom-lookups","toc":[{"title":"Un exemple d’expression de recherche","anchor":"a-lookup-example","children":[]},{"title":"Un exemple de transformateur","anchor":"a-transformer-example","children":[]},{"title":"Écriture d’une recherche abs__lt efficace","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"Un exemple de transformateur bilatéral","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Écriture d’implémentations alternatives pour des recherches existantes","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Comment Django détermine les recherches et les transformations qui sont utilisées","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"Guides pratiques","url":"/fr/5.1/howto/"}],"prev":{"docname":"howto/writing-migrations","title":"Écriture de migrations de base de données","url":"/fr/5.1/howto/writing-migrations/"},"next":{"docname":"howto/outputting-csv","title":"Création de contenu CSV","url":"/fr/5.1/howto/outputting-csv/"},"formats":{"html":"/fr/5.1/howto/custom-lookups/","markdown":"/fr/5.1/howto/custom-lookups.md","json":"/fr/5.1/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/5.1.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/fr/5.1/howto/custom-lookups/","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","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}