{"title":"Como escrever pesquisadores customizadas","version":"5.2","locale":"pt-br","docname":"howto/custom-lookups","url":"/pt-br/5.2/howto/custom-lookups/","canonical":"https://djangodocs.dev/pt-br/5.2/howto/custom-lookups/","summary":"Django oferece uma grande variedade de: ref:lookups embutidas <field-lookups> para filtragem (por exemplo, exact e icontains).","html":"<h1>Como escrever pesquisadores customizadas<a class=\"heading-anchor\" href=\"#how-to-write-custom-lookups\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django oferece uma grande variedade de: ref:lookups embutidas &lt;field-lookups&gt; para filtragem (por exemplo, <code class=\"docutils literal notranslate\">exact</code> e <code class=\"docutils literal notranslate\">icontains</code>). Esta documentação explica como escrever lookups personalizadas e como alterar o funcionamento de lookups existentes. Para as referências da API de lookups, consulte o: doc: /ref/models/lookups.</p>\n<section id=\"a-lookup-example\">\n<h2>Um exemplo de filtro<a class=\"heading-anchor\" href=\"#a-lookup-example\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Vamos começar com um pequeno pesquisador customizado. Nós iremos escrever um pesquisador customizado <code class=\"docutils literal notranslate\">ne</code> que irá funcionar de maneira contrária ao <code class=\"docutils literal notranslate\">exact</code>. <code class=\"docutils literal notranslate\">Author.objects.filter(name__ne='Jack')</code> irá ser traduzido para o 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=\"o\">&lt;&gt;</span> <span class=\"s1\">&#39;Jack&#39;</span>\n</code></pre></div>\n<p>Este SQL é independente, por isso, não precisa se preocupar com os bancos de dados diferentes.</p>\n<p>Há dois passos para fazer isso funcionar. Primeiramente nós precisamos implementar o filtro, então precisamos informar ao Django sobre isso:</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.db.models</span> <span class=\"kn\">import</span> Lookup\n\n\n<span class=\"k\">class</span> <span class=\"nc\">NotEqual</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s2\">&quot;ne&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_lhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params\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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n</code></pre></div>\n<p>Para registrar o pesquisador <code class=\"docutils literal notranslate\">NotEqual</code> vamos precisar chamar <code class=\"docutils literal notranslate\">register_lookup</code> na classe de campo que queremos que o pesquisador esteja disponível. Nesse caso, o pesquisador faz sentido para todas as subclasses de <code class=\"docutils literal notranslate\">Field</code>, então vamos registrá-lo diretamente com <code class=\"docutils literal notranslate\">Field</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=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Field\n\nField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>NotEqual<span class=\"p\">)</span>\n</code></pre></div>\n<p>O registro do filtro também pode ser feito usando um padrão de “decorator”:</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.db.models</span> <span class=\"kn\">import</span> Field\n\n\n<span class=\"nd\">@Field</span><span class=\"o\">.</span>register_lookup\n<span class=\"k\">class</span> <span class=\"nc\">NotEqualLookup</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>Agora podemos usar `` foo__ne`` para qualquer campo `` foo``. Tenha certeza de registrar antes de tentar criar qualquer “querysets” que o use. É possível colocar a implementação no `` models.py``, ou registar a lookup no método <code class=\"docutils literal notranslate\">ready()</code> do `` AppConfig``.</p>\n<p>Olhando mais perto da implementação, o primeiro atributo obrigatório é `` lookup_name``. Isso permite que o ORM entenda como interpretar `` name__ne`` e use `` NotEqual`` para gerar o SQL. Por convenção, estes nomes são sempre em strings caixa baixa contendo apenas letras, mas a única exigência é que não contenha a string `` __``.</p>\n<p>Quando então é necessário definir o método <code class=\"docutils literal notranslate\">as_sql</code>. Este recebe um objeto <code class=\"docutils literal notranslate\">SQL Compiler</code>, chamado <code class=\"docutils literal notranslate\">compiler</code>, e a conexão de banco de dados ativa. Os objetos <code class=\"docutils literal notranslate\">SQLCompiler</code> não são documentados, mas a única coisa que precisamos saber sobre eles é que eles tem um método <code class=\"docutils literal notranslate\">compile()</code> o qual retorna uma tupla contendo uma string SQL, e os parâmetros a serem interpolados naquela string. Na maioria dos casos você não precisa usá-lo diretamente e pode ser passá-lo para o <code class=\"docutils literal notranslate\">process_lhs()</code> e <code class=\"docutils literal notranslate\">process_rhs()</code>.</p>\n<p>A <code class=\"docutils literal notranslate\">Lookup</code> trabalha em dois valores, e <code class=\"docutils literal notranslate\">lhs</code> e <code class=\"docutils literal notranslate\">rhs</code>, entendendo como left-hand side e right-hand side. O lado esquerdo é geralmente uma referência de campo, mas pode ser qualquer coisa que implemente <a class=\"reference internal\" href=\"/pt-br/5.2/ref/models/lookups/#query-expression\"><span class=\"std std-ref\">query expression API</span></a>. O lado direito é o valor dado pelo usuário. No exemplo <code class=\"docutils literal notranslate\">Author.objects.filter (name__ne = 'Jack')</code>, o lado esquerdo é uma referência para o campo <code class=\"docutils literal notranslate\">name</code> campo do modelo <code class=\"docutils literal notranslate\">Author</code>, e <code class=\"docutils literal notranslate\">'Jack '</code> é o lado direito.</p>\n<p>Nós chamamos <code class=\"docutils literal notranslate\">process_lhs</code> e <code class=\"docutils literal notranslate\">process_rhs</code> para convertê-los para os valores que precisamos para SQL usando o objeto <code class=\"docutils literal notranslate\">compiler</code> descrito antes. Esses métodos retornam tuplas contendo alguns comandos SQL e os parâmetros a serem interpolados dentro destes comandos SQL, assim como nós precisamos para retornar do nosso método <code class=\"docutils literal notranslate\">as_sql</code>. No exemplo acima, <code class=\"docutils literal notranslate\">process_lhs</code> retorna <code class=\"docutils literal notranslate\">('&quot;author&quot;.&quot;name&quot;', [])</code> e <code class=\"docutils literal notranslate\">process_rhs</code> retorna <code class=\"docutils literal notranslate\">('&quot;%s&quot;', [ 'Jack' ])</code>. Neste exemplo não havia parâmetros para o lado esquerdo, mas isso depende do objeto que temos, portanto ainda precisamos incluí-los nos parâmetros que retornamos.</p>\n<p>FInalmente combinamos as partes em uma expressão SQL com <code class=\"docutils literal notranslate\">&lt;&gt;</code>, e fornecemos todos os parâmetros para a consulta. Então retornamos uma tupla contendo a string SQL gerada e os parâmetros.</p>\n</section>\n<section id=\"a-transformer-example\">\n<h2>Um exemplo de transformador<a class=\"heading-anchor\" href=\"#a-transformer-example\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>O lookup personalizado acima é boa, mas em alguns casos você queira ser capaz de lookups encadeadas. Por exemplo, vamos supor que estamos construindo uma aplicação onde queremos fazer uso do operador <code class=\"docutils literal notranslate\">abs()</code>. Temos um modelo <code class=\"docutils literal notranslate\">Experiment</code> que registra um valor inicial, o valor final e a mudança (início - fim). Gostaríamos de encontrar todos os experimentos em que a alteração foi igual a uma certa quantidade ( <code class=\"docutils literal notranslate\">Experiment.objects.filter (change__abs = 27)</code>), ou onde não exceda um certo montante ( <code class=\"docutils literal notranslate\">Experiment.objects.filter (change__abs__lt = 27)</code>).</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Nota</p>\n<p>Este exemplo é um pouco artificial, mas demonstra muito bem a gama de funcionalidades que é possível de uma maneira independente em um backend de banco de dados., e sem duplicar funcionalidades já existentes no Django.</p>\n</aside>\n<p>Nos vamos começar escrevendo um transformador <code class=\"docutils literal notranslate\">AbsoluteValue</code>. Isso vai usar a função SQL <code class=\"docutils literal notranslate\">ABS()</code> para transformar o valor antes da comparação</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.db.models</span> <span class=\"kn\">import</span> Transform\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    function <span class=\"o\">=</span> <span class=\"s2\">&quot;ABS&quot;</span>\n</code></pre></div>\n<p>Em seguida, vamos registrá-lo para `` IntegerField``</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.db.models</span> <span class=\"kn\">import</span> IntegerField\n\nIntegerField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>AbsoluteValue<span class=\"p\">)</span>\n</code></pre></div>\n<p>Agora nós podemos rodar as consultas que tínhamos antes. <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs=27)</code> irá gerar o seguinte 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=\"k\">SELECT</span> <span class=\"p\">...</span> <span class=\"k\">WHERE</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=\"o\">=</span> <span class=\"mi\">27</span>\n</code></pre></div>\n<p>Ao usar <code class=\"docutils literal notranslate\">Transform</code> em vez de <code class=\"docutils literal notranslate\">Lookup</code> somos capazes de usar outros pesquisadores em combinação depois. <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs__lt=27)</code> irá gerar o seguinte 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=\"k\">SELECT</span> <span class=\"p\">...</span> <span class=\"k\">WHERE</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=\"o\">&lt;</span> <span class=\"mi\">27</span>\n</code></pre></div>\n<p>Note que no caso de não haver nenhuma outra lookup especificada, o Django interpreta <code class=\"docutils literal notranslate\">change__abs = 27</code> como <code class=\"docutils literal notranslate\">change__abs__exact = 27</code>.</p>\n<p>Isso também permite que o resultado seja usado nas clausálas <code class=\"docutils literal notranslate\">ORDER BY</code> e <code class=\"docutils literal notranslate\">DISTINCT ON</code>. Por exemplo <code class=\"docutils literal notranslate\">Experiment.objects.order_by('change__abs')</code> gera:</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=\"p\">...</span> <span class=\"k\">ORDER</span> <span class=\"k\">BY</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=\"k\">ASC</span>\n</code></pre></div>\n<p>E em bancos de dados que tem suporte ao distinct em campos (como o PostgreSQL), <code class=\"docutils literal notranslate\">Experiment.objects.distinct('change__abs')</code> gera:</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=\"p\">...</span> <span class=\"k\">DISTINCT</span> <span class=\"k\">ON</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>Ao procurar quais lookups são permitidas depois de aplicar o <code class=\"docutils literal notranslate\">Transform</code>, o Django usa o atributo <code class=\"docutils literal notranslate\">output_field</code>. Não precisamos especificar isso aqui, já que não mudou, mas supondo que estivéssemos aplicando <code class=\"docutils literal notranslate\">AbsoluteValue</code> para algum campo que represente um tipo mais complexo (por exemplo um ponto relativo a uma origem ou um número complexo) então talvez querer especificar que o <code class=\"docutils literal notranslate\">transform</code> retorne um tipo <code class=\"docutils literal notranslate\">FloatField</code> para os próximos lookups. Isso pode ser feito adicionando um atributo <code class=\"docutils literal notranslate\">output_field</code> ao “transform”:</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.db.models</span> <span class=\"kn\">import</span> FloatField<span class=\"p\">,</span> Transform\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    function <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=\"nf\">output_field</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> FloatField<span class=\"p\">()</span>\n</code></pre></div>\n<p>Isso garante que novos filtros como o <code class=\"docutils literal notranslate\">abs__lte</code> se comportem como deveriam para um <code class=\"docutils literal notranslate\">FloatField</code>.</p>\n</section>\n<section id=\"writing-an-efficient-abs-lt-lookup\">\n<h2>Escrevendo um filtro <code class=\"docutils literal notranslate\">abs__lt</code> eficiente<a class=\"heading-anchor\" href=\"#writing-an-efficient-abs-lt-lookup\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Quando usar o filtro <code class=\"docutils literal notranslate\">abs</code> escrito acima, em alguns casos o SQL gerado não irá usar os índices de maneira eficiente. Em particular, quando usamos <code class=\"docutils literal notranslate\">change__abs__lt=27</code>, isso é equivalente a <code class=\"docutils literal notranslate\">change__gt=-27</code> e <code class=\"docutils literal notranslate\">change__lt=27</code>. (Para o caso <code class=\"docutils literal notranslate\">lte</code> podemos usar o <code class=\"docutils literal notranslate\">BETWEEN</code> do SQL).</p>\n<p>Então optaríamos por <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs__lt=27)</code> para gerar o seguinte 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=\"k\">SELECT</span> <span class=\"p\">..</span> <span class=\"k\">WHERE</span> <span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span> <span class=\"o\">&lt;</span> <span class=\"mi\">27</span> <span class=\"k\">AND</span> <span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span> <span class=\"o\">&gt;</span> <span class=\"o\">-</span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>A implementação é:</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.db.models</span> <span class=\"kn\">import</span> Lookup\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValueLessThan</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s2\">&quot;lt&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> compiler<span class=\"o\">.</span>compile<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>lhs<span class=\"o\">.</span>lhs<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params <span class=\"o\">+</span> lhs_params <span class=\"o\">+</span> rhs_params\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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">,</span> lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n\n\nAbsoluteValue<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>AbsoluteValueLessThan<span class=\"p\">)</span>\n</code></pre></div>\n<p>Há algumas coisas notáveis ​​acontecendo. Em primeiro lugar, <code class=\"docutils literal notranslate\">AbsoluteValueLessThan</code> não está chamando <code class=\"docutils literal notranslate\">process_lhs ()</code>. Em vez disso ele ignora a transformação do <code class=\"docutils literal notranslate\">lhs</code> feito por <code class=\"docutils literal notranslate\">AbsoluteValue</code> e usa o <code class=\"docutils literal notranslate\">lhs</code> original. Ou seja, queremos pegar `` “experiments”.”change” `` não <code class=\"docutils literal notranslate\">ABS( &quot;experiments&quot;. &quot;change&quot;) ``. Referindo-se diretamente ao ``self.lhs.lhs</code> é tão seguro quanto o <code class=\"docutils literal notranslate\">AbsoluteValueLessThan</code> pode ser acessado diretamente do filtro <code class=\"docutils literal notranslate\">AbsoluteValue</code>, que é <code class=\"docutils literal notranslate\">lhs</code> é sempre uma instância de <code class=\"docutils literal notranslate\">AbsoluteValue</code>.</p>\n<p>Note também que como ambos os lados são usados ​​várias vezes na consulta os parâmetros precisam conter <code class=\"docutils literal notranslate\">lhs_params</code> e <code class=\"docutils literal notranslate\">rhs_params</code> várias vezes.</p>\n<p>A consulta final faz a inversão ( <code class=\"docutils literal notranslate\">27</code> para `` -27``) diretamente no banco de dados. A razão para isso é que, se o `` self.rhs`` é algo mais do que um valor inteiro simples (por exemplo, uma referência <code class=\"docutils literal notranslate\">F()</code> ) não podemos fazer as transformações em Python.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Nota</p>\n<p>Na verdade, a maioria das filtros com <code class=\"docutils literal notranslate\">__abs</code> poderiam ser implementados como consultas de intervalos como esta, e na maioria dos “backends” de banco de dados, é provável que seja mais sensato fazê-lo já que podería fazer uso dos índices. No entanto, com PostgreSQL você pode querer adicionar um índice na <code class=\"docutils literal notranslate\">abs(change)</code> o que permitiria que essas consultas fossem muito eficientes.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>Um exemplo bilateral de “transforme”<a class=\"heading-anchor\" href=\"#a-bilateral-transformer-example\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>O exemplo <code class=\"docutils literal notranslate\">AbsoluteValue</code> discutido anteriormente é uma transformação que se aplica para o lado esquerdo da lookup. Pode haver alguns casos onde você quer que a transformação seja aplicada tanto para o lado esquerdo quanto para o lado direito. Por exemplo, se você quiser filtrar um queryset com base em uma igualdade de lado esquerdo e direito insensivelmente para alguma função SQL.</p>\n<p>Vamos examinar transformações insensíveis a maiúsculas-minúsculas. Essa transformação não é muito útil na prática já que o Django já contém vários pesquisadores como esse built-in, mas é uma boa demonstração de transformações bilaterais agnóstica ao banco de dados.</p>\n<p>Definimos um “transformer” de <code class=\"docutils literal notranslate\">UpperCase</code> que usa a função <code class=\"docutils literal notranslate\">UPPER()</code> do SQL para transformar os valores antes da comparação. Definimos :attr: bilateral = True &lt;django.db.models.Transform.bilateral&gt; para indicar que essa transformação deve ser aplicada a ambos <code class=\"docutils literal notranslate\">lhs</code> e <code class=\"docutils literal notranslate\">rhs</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=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Transform\n\n\n<span class=\"k\">class</span> <span class=\"nc\">UpperCase</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s2\">&quot;upper&quot;</span>\n    function <span class=\"o\">=</span> <span class=\"s2\">&quot;UPPER&quot;</span>\n    bilateral <span class=\"o\">=</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>Em seguida, registre</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.db.models</span> <span class=\"kn\">import</span> CharField<span class=\"p\">,</span> TextField\n\nCharField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>UpperCase<span class=\"p\">)</span>\nTextField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>UpperCase<span class=\"p\">)</span>\n</code></pre></div>\n<p>Agora, a queryset <code class=\"docutils literal notranslate\">Author.objects.filter(name__upper=&quot;doe&quot;)</code> irá gerar uma consulta insensível a maiúsculas-minúsculas como essa:</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=\"p\">...</span> <span class=\"k\">WHERE</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=\"o\">=</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>Escrever implementações alternativas para filtros existentes<a class=\"heading-anchor\" href=\"#writing-alternative-implementations-for-existing-lookups\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Às vezes, diferentes fornecedores de banco de dados requerem diferentes SQL para a mesma operação. Para este exemplo, vamos reescrever uma implementação personalizada para o do operador NotEqual para o MySQL. Em vez de <code class=\"docutils literal notranslate\">&lt;&gt;</code> usaremos o operador <code class=\"docutils literal notranslate\">!=</code>. (Note que, na realidade, quase todos os bancos de dados suportam ambos, incluindo todas as bases de dados oficiais apoiadas pelo Django).</p>\n<p>Nós podemos mudar o comportamento em um backend específico criado pela subclasse de <code class=\"docutils literal notranslate\">NotEqual</code> com um método <code class=\"docutils literal notranslate\">as_mysql</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=\"nc\">MySQLNotEqual</span><span class=\"p\">(</span>NotEqual<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">as_mysql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">,</span> <span class=\"o\">**</span>extra_context<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_lhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params\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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n\n\nField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>MySQLNotEqual<span class=\"p\">)</span>\n</code></pre></div>\n<p>Podemos então registrá-lo com <code class=\"docutils literal notranslate\">Field</code>. Ele toma o lugar da classe <code class=\"docutils literal notranslate\">NotEqual</code> original já que tem o mesmo <code class=\"docutils literal notranslate\">lookup_name</code>.</p>\n<p>Ao compilar uma consulta, o Django primeiro procura pelos métodos <code class=\"docutils literal notranslate\">as_%s % connection.vendor</code>, e depois para <code class=\"docutils literal notranslate\">as_sql</code>. Os nomes de fornecedores para os back-ends suportados são <code class=\"docutils literal notranslate\">sqlite</code>, <code class=\"docutils literal notranslate\">postgresql</code>, <code class=\"docutils literal notranslate\">oracle</code>  e <code class=\"docutils literal notranslate\">mysql</code>.</p>\n</section>\n<section id=\"how-django-determines-the-lookups-and-transforms-which-are-used\">\n<h2>Como o Django determina quais filtros e “transforms” são usados<a class=\"heading-anchor\" href=\"#how-django-determines-the-lookups-and-transforms-which-are-used\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Em alguns casos, talvez queira mudar dinamicamente qual <code class=\"docutils literal notranslate\">Transform</code> ou filtro é devolvido com base no nome passado, em vez de corrigí-lo. Como exemplo, você pode ter um campo o qual armazena coordenadas ou uma dimensão arbitrária, e deseja permitir uma sintaxe como <code class=\"docutils literal notranslate\">.filter (coords__x7=4)</code> para retornar os objetos onde a 7ª coordenada tem valor 4. Para fazer isso, substitua <code class=\"docutils literal notranslate\">get_lookup</code> com algo como:</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=\"nc\">CoordinatesField</span><span class=\"p\">(</span>Field<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_lookup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> lookup_name<span class=\"p\">):</span>\n        <span class=\"k\">if</span> lookup_name<span class=\"o\">.</span>startswith<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                dimension <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span>lookup_name<span class=\"o\">.</span>removeprefix<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> get_coordinate_lookup<span class=\"p\">(</span>dimension<span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>get_lookup<span class=\"p\">(</span>lookup_name<span class=\"p\">)</span>\n</code></pre></div>\n<p>Você deve então definir `` get_coordinate_lookup`` adequadamente para retornar uma subclasse de <code class=\"docutils literal notranslate\">Lookup</code> a qual lida com o valor relevante da <code class=\"docutils literal notranslate\">dimension</code>.</p>\n<p>Existe um método de nome semelhante chamado <code class=\"docutils literal notranslate\">get_transform() ``. `` Get_lookup () `` deve sempre retornar uma subclasse de ``Lookup</code>, e <code class=\"docutils literal notranslate\">get_transform()</code> uma subclasse de  <code class=\"docutils literal notranslate\">Transform</code>. É importante lembrar que objetos do tipo <code class=\"docutils literal notranslate\">Transform</code> podem ainda ser filtrados, e objetos do tipo <code class=\"docutils literal notranslate\">Lookup</code> não.</p>\n<p>Ao filtrar, se houver apenas um nome de filtro remanescente a ser resolvido, olhamos para um <code class=\"docutils literal notranslate\">Lookup</code>. Se houver vários nomes, ele irá procurar por um <code class=\"docutils literal notranslate\">Transform</code>. Em uma situação onde há apenas um nome e um <code class=\"docutils literal notranslate\">Lookup</code> não é encontrado, procuramos por um <code class=\"docutils literal notranslate\">Transform</code> e então o  filtro <code class=\"docutils literal notranslate\">exact</code> naquele <code class=\"docutils literal notranslate\">Transform</code>. Todas as sequências de chamadas sempre terminam com um <code class=\"docutils literal notranslate\">Lookup</code>. Para esclarecer:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mylookup)</code> irá chamar myfield.get_lookup(‘mylookup’)`.</p></li>\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mytransform__mylookup)</code> irá chamar <code class=\"docutils literal notranslate\">myfield.get_transform('mytransform')</code>, e  em seguida <code class=\"docutils literal notranslate\">mytransform.get_lookup('mylookup')</code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mytransform)</code> irá chamar primeiro <code class=\"docutils literal notranslate\">myfield.get_lookup( 'mytransform')</code>, o qual irá falhar, por isso vai retornar e chamar <code class=\"docutils literal notranslate\">myfield.get_transform('mytransform')</code> e em seguida, <code class=\"docutils literal notranslate\">mytransform.get_lookup( &quot;exact&quot;)</code>.</p></li>\n</ul>\n</section>","rootId":"how-to-write-custom-lookups","toc":[{"title":"Um exemplo de filtro","anchor":"a-lookup-example","children":[]},{"title":"Um exemplo de transformador","anchor":"a-transformer-example","children":[]},{"title":"Escrevendo um filtro abs__lt eficiente","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"Um exemplo bilateral de “transforme”","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Escrever implementações alternativas para filtros existentes","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Como o Django determina quais filtros e “transforms” são usados","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"How-to guides","url":"/pt-br/5.2/howto/"}],"prev":{"docname":"howto/writing-migrations","title":"How to create database migrations","url":"/pt-br/5.2/howto/writing-migrations/"},"next":{"docname":"howto/outputting-csv","title":"How to create CSV output","url":"/pt-br/5.2/howto/outputting-csv/"},"formats":{"html":"/pt-br/5.2/howto/custom-lookups/","markdown":"/pt-br/5.2/howto/custom-lookups.md","json":"/pt-br/5.2/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/pt-br/5.2/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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}