{"title":"Pesquisas personalizadas","version":"1.9","locale":"pt-br","docname":"howto/custom-lookups","url":"/pt-br/1.9/howto/custom-lookups/","canonical":"https://djangodocs.dev/pt-br/1.9/howto/custom-lookups/","summary":"Django oferece uma grande variedade de: ref: pesquisas embutidos <field-lookups> `Para filtragem (por exemplo, e exact` icontains``). Esta documentação explica como…","html":"<h1>Pesquisas personalizadas<a class=\"heading-anchor\" href=\"#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: pesquisas embutidos &lt;field-lookups&gt; `Para filtragem (por exemplo, e exact` icontains``). 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-simple-lookup-example\">\n<h2>Um simples exemple de pesquisa<a class=\"heading-anchor\" href=\"#a-simple-lookup-example\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Vamos iniciar com uma simples pesquisa personalizada. Escreveremos uma simples pesquisa <code class=\"docutils literal notranslate\"><span class=\"pre\">ne</span></code> que funciona em frente ao <code class=\"docutils literal notranslate\"><span class=\"pre\">exato</span></code>. <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>Author.objects.filter(name__ne=’Jack’) traduzindo para SQL.</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=\"s2\">&quot;author&quot;</span><span class=\"o\">.</span><span class=\"s2\">&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á duas etapas para fazer este trabalho. Em primeiro lugar precisamos implementar a “lookup”, então precisamos dizer ao Django sobre ele. A implementação é bastante simples</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<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=\"s1\">&#39;ne&#39;</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=\"s1\">&#39;</span><span class=\"si\">%s</span><span class=\"s1\"> &lt;&gt; </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</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>Para registrar a lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> precisamos somente chamar <code class=\"docutils literal notranslate\"><span class=\"pre\">register_lookup</span></code> no campo da classe que queremos que a lookup esteja disponível. Neste caso, a lookup faz sentido em todos os  <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> da sub-classe, então registramos isso com `` Field`` diretamente</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.fields</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\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>O registro da “lookup” também pode ser feito usando um pattern decorador</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.fields</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\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>\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n<aside class=\"version-note version-changed\" data-version=\"1.8\">\n<p class=\"version-note-title\">Changed in Django 1.8</p><p>foi adicionado a capacidade de usar o pattern decorator.</p>\n</aside>\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\"><span class=\"pre\">ready()</span></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>We then need to define the <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code> method. This takes a <code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code>\nobject, called <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code>,  and the active database connection.\n<code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code> objects are not documented, but the only thing we need to know\nabout them is that they have a <code class=\"docutils literal notranslate\"><span class=\"pre\">compile()</span></code> method which returns a tuple\ncontaining an SQL string, and the parameters to be interpolated into that\nstring. In most cases, you don’t need to use it directly and can pass it on to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs()</span></code>.</p>\n<p>A <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> trabalha em dois valores, e <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> e  <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></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 :ref: query expression API &lt;query-expression&gt;. O lado direito é o valor dado pelo usuário. No exemplo <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter</span> <span class=\"pre\">(name__ne</span> <span class=\"pre\">=</span> <span class=\"pre\">'Jack')</span> <span class=\"pre\">``,</span> <span class=\"pre\">o</span> <span class=\"pre\">lado</span> <span class=\"pre\">esquerdo</span> <span class=\"pre\">é</span> <span class=\"pre\">uma</span> <span class=\"pre\">referência</span> <span class=\"pre\">para</span> <span class=\"pre\">o</span> <span class=\"pre\">campo</span> <span class=\"pre\">``name</span></code> campo do modelo <code class=\"docutils literal notranslate\"><span class=\"pre\">Author</span></code>, e `` ‘Jack ‘ `` é o lado direito.</p>\n<p>Nós chamamos e <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> e  <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> para convertê-los para os valores que precisamos para SQL usando o objeto <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> descrito antes. Esses métodos retornam tuplas contendo alguns SQL e os parâmetros a serem interpolados dentro deste SQL, assim como nós precisamos para retornar do nosso método <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. No exemplo acima, <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> retorna <code class=\"docutils literal notranslate\"><span class=\"pre\">(</span> <span class=\"pre\">&quot;autor&quot;.</span> <span class=\"pre\">&quot;Nome&quot;</span> <span class=\"pre\">',</span> <span class=\"pre\">[])</span> <span class=\"pre\">``</span> <span class=\"pre\">e</span> <span class=\"pre\">``process_rhs</span></code> retorna <code class=\"docutils literal notranslate\"><span class=\"pre\">(</span> <span class=\"pre\">&quot;%</span> <span class=\"pre\">s&quot;',</span> <span class=\"pre\">[</span> <span class=\"pre\">'Jack'</span> <span class=\"pre\">])</span></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>Finally we combine the parts into an SQL expression with <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code>, and supply all\nthe parameters for the query. We then return a tuple containing the generated\nSQL string and the parameters.</p>\n</section>\n<section id=\"a-simple-transformer-example\">\n<h2>Um exemplo simples transformador<a class=\"heading-anchor\" href=\"#a-simple-transformer-example\"><span class=\"visually-hidden\">Link para este cabeçalho</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>A 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\"><span class=\"pre\">abs()</span></code>. Temos um modelo <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment</span></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\"><span class=\"pre\">Experiment.objects.filter</span> <span class=\"pre\">(change__abs</span> <span class=\"pre\">=</span> <span class=\"pre\">27)</span></code>), ou onde não exceda um certo montante ( <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter</span> <span class=\"pre\">(change__abs__lt</span> <span class=\"pre\">=</span> <span class=\"pre\">27)</span></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>Vamos começar por escrever um tradutor <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>. Isto irá usar a função SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS</span> <span class=\"pre\">()</span></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=\"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<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=\"s1\">&#39;abs&#39;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;ABS&#39;</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=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">IntegerField</span>\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>agora podemos executar as queries que tínhamos antes. <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>Experiment.objects.filter (change__abs = 27) `` irá gerar o seguinte SQL</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=\"n\">SELECT</span> <span class=\"o\">...</span> <span class=\"n\">WHERE</span> <span class=\"n\">ABS</span><span class=\"p\">(</span><span class=\"s2\">&quot;experiments&quot;</span><span class=\"o\">.</span><span class=\"s2\">&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 `` Transform`` ao invés de <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> isso significa que somos capazes de encadear lookups umas as outras. Então <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter</span> <span class=\"pre\">(change__abs__lt</span> <span class=\"pre\">=</span> <span class=\"pre\">27)</span></code> irá gerar o seguinte SQL</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=\"n\">SELECT</span> <span class=\"o\">...</span> <span class=\"n\">WHERE</span> <span class=\"n\">ABS</span><span class=\"p\">(</span><span class=\"s2\">&quot;experiments&quot;</span><span class=\"o\">.</span><span class=\"s2\">&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-se que no caso não há nenhuma outra lookup especificada, o Django interpreta <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs</span> <span class=\"pre\">=</span> <span class=\"pre\">27</span></code> como <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__exact</span> <span class=\"pre\">=</span> <span class=\"pre\">27</span></code>.</p>\n<p>Quando olhamos par quais lookups são permitidas depois de ter aplicado o  <code class=\"docutils literal notranslate\"><span class=\"pre\">Trnasform</span></code>, Django usa o atibuto òutput_field`. Não é necessário especificar isso aqui, já que não muda, más supondo que fosse aplicado <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue``para</span> <span class=\"pre\">algum</span> <span class=\"pre\">campo</span> <span class=\"pre\">que</span> <span class=\"pre\">represente</span> <span class=\"pre\">um</span> <span class=\"pre\">tipo</span> <span class=\"pre\">mais</span> <span class=\"pre\">complexo</span> <span class=\"pre\">(por</span> <span class=\"pre\">exemplo</span> <span class=\"pre\">um</span> <span class=\"pre\">ponto</span> <span class=\"pre\">reativo</span> <span class=\"pre\">a</span> <span class=\"pre\">uma</span> <span class=\"pre\">origem</span> <span class=\"pre\">ou</span> <span class=\"pre\">um</span> <span class=\"pre\">número</span> <span class=\"pre\">complexo)</span> <span class=\"pre\">então</span> <span class=\"pre\">talvez</span> <span class=\"pre\">quereríamos</span> <span class=\"pre\">especificar</span>&#160; <span class=\"pre\">que</span> <span class=\"pre\">retornasse</span> <span class=\"pre\">um</span> <span class=\"pre\">tipo</span> <span class=\"pre\">``FloatField</span></code> para próximas lookups. Isso pode ser feito adicionando um atributo <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>òutput_field``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=\"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<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=\"s1\">&#39;abs&#39;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;ABS&#39;</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>Isso garante que novas pesquisas como <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lte</span></code> se comportem como fariam para um <code class=\"docutils literal notranslate\"><span class=\"pre\">FloatField</span></code>.</p>\n</section>\n<section id=\"writing-an-efficient-abs-lt-lookup\">\n<h2>Escrevendo uma lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lt</span></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 usado a lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">abs</span></code> escrita acima, o SQL gerado não irá usar índices  de maneira eficiente em alguns casos. Em particular, quando usado <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__lt=27</span></code>, é equivalente a <code class=\"docutils literal notranslate\"><span class=\"pre\">change__gt=-27</span></code> e <code class=\"docutils literal notranslate\"><span class=\"pre\">change__lt=27</span></code>. (Para o caso <code class=\"docutils literal notranslate\"><span class=\"pre\">lte</span></code> podemos usar o SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">BETWEEN</span></code>).</p>\n<p>Então nós gostaríamos <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter</span> <span class=\"pre\">(change__abs__lt=27)</span></code> para gerar o seguinte SQL:</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=\"n\">SELECT</span> <span class=\"o\">..</span> <span class=\"n\">WHERE</span> <span class=\"s2\">&quot;experiments&quot;</span><span class=\"o\">.</span><span class=\"s2\">&quot;change&quot;</span> <span class=\"o\">&lt;</span> <span class=\"mi\">27</span> <span class=\"n\">AND</span> <span class=\"s2\">&quot;experiments&quot;</span><span class=\"o\">.</span><span class=\"s2\">&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=\"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<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=\"s1\">&#39;lt&#39;</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=\"s1\">&#39;</span><span class=\"si\">%s</span><span class=\"s1\"> &lt; </span><span class=\"si\">%s</span><span class=\"s1\"> AND </span><span class=\"si\">%s</span><span class=\"s1\"> &gt; -</span><span class=\"si\">%s</span><span class=\"s1\">&#39;</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<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>Há algumas coisas notáveis ​​acontecendo. Em primeiro lugar, <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code> não está chamando <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span> <span class=\"pre\">()</span></code>. Em vez disso ele ignora a transformação do <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> feito por <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> e usa o <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> original. Ou seja, queremos pegar `` “experiments”.”change” `` não <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS(</span> <span class=\"pre\">&quot;experiments&quot;.</span> <span class=\"pre\">&quot;change&quot;)</span> <span class=\"pre\">``.</span> <span class=\"pre\">Referindo-se</span> <span class=\"pre\">diretamente</span> <span class=\"pre\">a</span> <span class=\"pre\">``self.lhs.lhs</span></code> é tão seguro quanto <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code>  pode ser acessado diretamente da lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>, que é a <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> é sempre uma instância de <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></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\"><span class=\"pre\">lhs_params</span></code> e <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs_params</span></code> várias vezes.</p>\n<p>A consulta final faz a inversão ( <code class=\"docutils literal notranslate\"><span class=\"pre\">27</span></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\"><span class=\"pre\">F()</span></code> ) que 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 lookups com <code class=\"docutils literal notranslate\"><span class=\"pre\">__abs</span></code> poderias ser implementadas 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 em na <code class=\"docutils literal notranslate\"><span class=\"pre\">abs(change)</span></code> o que permitiria que essas consultas serem muito eficientes.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>Um exemplo bilateral transformador<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\"><span class=\"pre\">AbsoluteValue</span></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 inperseptível para alguma função SQL.</p>\n<p>Vamos examinar o exemplo simples de transformação case-insensitive aqui. Essa transformação não é muito útil na prática, como Django já vem com um monte de pesquisas de maiúsculas e minúsculas embutidos, mas será uma boa demonstração de transformações bilaterais de uma forma agnóstica ao banco de dados.</p>\n<p>Definimos um transformador <code class=\"docutils literal notranslate\"><span class=\"pre\">UpperCase</span></code> que usa a função SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">UPPER()</span></code> para transformar os valores antes de comparação. Definimos :attr: bilateral = True &lt;django.db.models.Transform.bilateral&gt; para indicar que essa transformação deverá aplicar-se a <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> e <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<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=\"s1\">&#39;upper&#39;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;UPPER&#39;</span>\n    <span class=\"n\">bilateral</span> <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=\"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<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>Agora, o queryset <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__upper</span> <span class=\"pre\">=</span> <span class=\"pre\">&quot;doe&quot;)</span></code> irá gerar uma query case-insensitive como esta:</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=\"n\">SELECT</span> <span class=\"o\">...</span> <span class=\"n\">WHERE</span> <span class=\"n\">UPPER</span><span class=\"p\">(</span><span class=\"s2\">&quot;author&quot;</span><span class=\"o\">.</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"n\">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 pesquisas 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 MySQL para o operador NotEqual. Em vez de <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code> usaremos o operador <code class=\"docutils literal notranslate\"><span class=\"pre\">!=</span></code>. (Note que, na realidade, quase todos os bancos de dados suportam ambos, incluindo todas as bases de dados oficiais apoiados por Django).</p>\n<p>Nós podemos mudar o comportamento em um backend específico, criando uma subclasse de <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> com um método <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>\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=\"s1\">&#39;</span><span class=\"si\">%s</span><span class=\"s1\"> != </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</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<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>Podemos então registrá-lo com <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>. Ele toma o lugar da classe <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> original já que tem o mesmo <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>.</p>\n<p>Ao compilar uma consulta, Django primeiro procura pelos métodos <code class=\"docutils literal notranslate\"><span class=\"pre\">as_%s</span> <span class=\"pre\">%</span> <span class=\"pre\">connection.vendor</span></code>, e depois para <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Os nomes de fornecedores para os back-ends suportador são  <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>  e <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>Como o Django determina as lookups e transformações que 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\"><span class=\"pre\">Transform</span></code> ou <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> é devolvido com base no nome passado, em vez de corrigi-lo. Como exemplo, é possível ter um campo que armazena coordenadas ou uma dimensão arbitrária, e deseja permitir que uma sintaxe como <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter</span> <span class=\"pre\">(coords__x7=4)</span></code> para retornar os objetos onde a 7ª coordenada tem valor 4. Para fazer isso, substitua <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup</span></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=\"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=\"s1\">&#39;x&#39;</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=\"p\">[</span><span class=\"mi\">1</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=\"n\">CoordinatesField</span><span class=\"p\">,</span> <span class=\"bp\">self</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>Defina então o `` get_coordinate_lookup`` adequadamente para retornar uma subclasse <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> que lida com o valor relevante da <code class=\"docutils literal notranslate\"><span class=\"pre\">dimension</span></code>.</p>\n<p>Existe um método de nome semelhante chamado <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span> <span class=\"pre\">``.</span> <span class=\"pre\">``</span> <span class=\"pre\">Get_lookup</span> <span class=\"pre\">()</span> <span class=\"pre\">``</span> <span class=\"pre\">deve</span> <span class=\"pre\">sempre</span> <span class=\"pre\">retornar</span> <span class=\"pre\">uma</span> <span class=\"pre\">subclasse</span> <span class=\"pre\">de</span> <span class=\"pre\">``Lookup</span></code>, e <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code> uma subclasse de  <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. É importante lembrar que objetos do tipo <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> podem ainda ser filtrados, e objetos do tipo <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> não podem.</p>\n<p>Ao filtrar, se houver apenas um nome lookup remanescente a ser resolvido, olhamos para um <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. Se houver vários nomes, ele irá procurar por um <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Em uma situação onde há apenas um nome e um <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> não é encontrado, procuramos por um <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> e então o  lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> naquele <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Todas as sequências de chamadas sempre terminam com um <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. Para esclarecer:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mylookup)</span></code> irá chamar myfield.get_lookup(‘mylookup’)`.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mytransform__mylookup)</span></code> irá chamar <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code>, e  em seguida <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> irá chamar primeiro <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup(</span> <span class=\"pre\">'mytransform')</span></code>, o qual irá falhar, por isso vai retornar e chamar <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code> e em seguida, <code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup(</span> <span class=\"pre\">&quot;exact&quot;)</span></code>.</p></li>\n</ul>\n</section>","rootId":"custom-lookups","toc":[{"title":"Um simples exemple de pesquisa","anchor":"a-simple-lookup-example","children":[]},{"title":"Um exemplo simples transformador","anchor":"a-simple-transformer-example","children":[]},{"title":"Escrevendo uma lookup abs__lt eficiente","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"Um exemplo bilateral transformador","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Escrever implementações alternativas para pesquisas existentes","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Como o Django determina as lookups e transformações que são usados","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"Guias de “como fazer”","url":"/pt-br/1.9/howto/"}],"prev":{"docname":"howto/custom-model-fields","title":"Escrevendo campos personalizados de modelos.","url":"/pt-br/1.9/howto/custom-model-fields/"},"next":{"docname":"howto/custom-template-tags","title":"“Template tags” e filtros customizados","url":"/pt-br/1.9/howto/custom-template-tags/"},"formats":{"html":"/pt-br/1.9/howto/custom-lookups/","markdown":"/pt-br/1.9/howto/custom-lookups.md","json":"/pt-br/1.9/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/1.9.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/pt-br/1.9/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","fr","ja","id","pt-br","es"]}