{"title":"カスタムのルックアップ","version":"2.1","locale":"ja","docname":"howto/custom-lookups","url":"/ja/2.1/howto/custom-lookups/","canonical":"https://djangodocs.dev/ja/2.1/howto/custom-lookups/","summary":"Django には (たとえば exact や icontains などの) フィルタリングを行う built-in lookups が数多くあります。このドキュメントでは、カスタムルックアップをどのように作るかや、既存のルックアップの動作をどのようにして変更するかについて説明します。ルックアップの API…","html":"<h1>カスタムのルックアップ<a class=\"heading-anchor\" href=\"#custom-lookups\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django には (たとえば <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> や <code class=\"docutils literal notranslate\"><span class=\"pre\">icontains</span></code> などの) フィルタリングを行う <a class=\"reference internal\" href=\"/ja/2.1/ref/models/querysets/#field-lookups\"><span class=\"std std-ref\">built-in lookups</span></a> が数多くあります。このドキュメントでは、カスタムルックアップをどのように作るかや、既存のルックアップの動作をどのようにして変更するかについて説明します。ルックアップの API リファレンスについては <a class=\"reference internal\" href=\"/ja/2.1/ref/models/lookups/\"><span class=\"doc\">Lookup API reference</span></a> を参照してください。</p>\n<section id=\"a-simple-lookup-example\">\n<h2>シンプルなルックアップの例<a class=\"heading-anchor\" href=\"#a-simple-lookup-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>シンプルなカスタムルックアップからはじめましょう。これから、<code class=\"docutils literal notranslate\"><span class=\"pre\">ne</span></code> というカスタムルックアップを書いていきます。このルックアップは、<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> は、次の 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>この SQL はバックエンドに依存しない書き方になっているため、別のデータベースについて心配する必要はありません。</p>\n<p>このルックアップを動作させるためには、2つのステップが必要です。第1に、ルックアップを実装する必要があります。第2に、Django に実装したルックアップの情報を伝えて上げる必要があります。実装に関しては、次のようにとてもわかりやすい形です。</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><code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> ルックアップを登録する方法は、ルックアップを利用できるようにしたいフィールドクラス上で <code class=\"docutils literal notranslate\"><span class=\"pre\">register_lookup</span></code> を呼び出すだけです。今回のルックアップは、<code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> のすべてのサブクラス上で意味を持つため、親クラスの <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.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>ルックアップは、デコレータパタンを使っても登録できます。</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<p>これ以降、どのようなフィールドであっても <code class=\"docutils literal notranslate\"><span class=\"pre\">foo</span></code> に対しては <code class=\"docutils literal notranslate\"><span class=\"pre\">foo__ne</span></code> が利用できます。なお、これを用いるクエリーセットを生成するならば、それ以前にルックアップの登録を行っておく必要があります。実装する場所は <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code> ファイル内で行ってもよいし、<code class=\"docutils literal notranslate\"><span class=\"pre\">AppConfig</span></code> 内の <code class=\"docutils literal notranslate\"><span class=\"pre\">ready()</span></code> メソッドにてルックアップの登録を行うのでも構いません。</p>\n<p>実装の詳細について見ると、最初に必要な属性は <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code> です。この属性があると、ORM が <code class=\"docutils literal notranslate\"><span class=\"pre\">name_ne</span></code> を解釈できるようになり、<code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> を使って SQL を生成できます。慣習として、こうした名前は常に小文字のアルファベットのみからなる文字列にしますが、必ず守らなければならない制約は、文字列 <code class=\"docutils literal notranslate\"><span class=\"pre\">__</span></code> を決して含んではならないということです。</p>\n<p>次に、&quot;as_sql&quot; メソッドを定義する必要があります。これには &quot;compiler&quot; という&quot;SQL Compiler&quot; オブジェクトと、アクティブなデータベース接続を必要とします。&quot;SQL Compiler&quot; オブジェクトについてのドキュメントはありませんが、それがSQL文字列を含むタプルと文字列に挿入されるパラメータを返す``compile()`` メソッドを持つ、ということだけ知っていれば十分です。ほとんどの場合、これを直接用いる必要はなく、<code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code> および <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> works against two values, <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></code>, standing for\nleft-hand side and right-hand side. The left-hand side is usually a field\nreference, but it can be anything implementing the <a class=\"reference internal\" href=\"/ja/2.1/ref/models/lookups/#query-expression\"><span class=\"std std-ref\">query expression API</span></a>. The right-hand is the value given by the user. In the\nexample <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code>, the left-hand side is a\nreference to the <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> field of the <code class=\"docutils literal notranslate\"><span class=\"pre\">Author</span></code> model, and <code class=\"docutils literal notranslate\"><span class=\"pre\">'Jack'</span></code> is the\nright-hand side.</p>\n<p>We call <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> to convert them into the values we\nneed for SQL using the <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> object described before. These methods\nreturn tuples containing some SQL and the parameters to be interpolated into\nthat SQL, just as we need to return from our <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code> method. In the above\nexample, <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> returns <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;author&quot;.&quot;name&quot;',</span> <span class=\"pre\">[])</span></code> and\n<code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> returns <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;%s&quot;',</span> <span class=\"pre\">['Jack'])</span></code>. In this example there were no\nparameters for the left hand side, but this would depend on the object we have,\nso we still need to include them in the parameters we return.</p>\n<p>最後に、これらの部分を `` &lt;&gt; <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>を使ってSQL式にまとめ、クエリのすべてのパラメータを指定します。その後、生成されたSQL文字列とパラメータを含むタプルを返します。</p>\n</section>\n<section id=\"a-simple-transformer-example\">\n<h2>シンプルな変換の例<a class=\"heading-anchor\" href=\"#a-simple-transformer-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The custom lookup above is great, but in some cases you may want to be able to\nchain lookups together. For example, let's suppose we are building an\napplication where we want to make use of the <code class=\"docutils literal notranslate\"><span class=\"pre\">abs()</span></code> operator.\nWe have an <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment</span></code> model which records a start value, end value, and the\nchange (start - end). We would like to find all experiments where the change\nwas equal to a certain amount (<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code>),\nor where it did not exceed a certain amount\n(<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\">注釈</p>\n<p>This example is somewhat contrived, but it nicely demonstrates the range of\nfunctionality which is possible in a database backend independent manner,\nand without duplicating functionality already in Django.</p>\n</aside>\n<p>We will start by writing an <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> transformer. This will use the SQL\nfunction <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS()</span></code> to transform the value before comparison:</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>Next, let's register it for <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<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>We can now run the queries we had before.\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code> will generate the following 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>By using <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> instead of <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> it means we are able to chain\nfurther lookups afterwards. So\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> will generate the following\nSQL:</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 that in case there is no other lookup specified, Django interprets\n<code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs=27</span></code> as <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__exact=27</span></code>.</p>\n<p>This also allows the result to be used in <code class=\"docutils literal notranslate\"><span class=\"pre\">ORDER</span> <span class=\"pre\">BY</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">DISTINCT</span> <span class=\"pre\">ON</span></code>\nclauses. For example <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.order_by('change__abs')</span></code> generates:</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\">ORDER</span> <span class=\"n\">BY</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=\"n\">ASC</span>\n</code></pre></div>\n<p>And on databases that support distinct on fields (such as PostgreSQL),\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.distinct('change__abs')</span></code> generates:</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\">DISTINCT</span> <span class=\"n\">ON</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>\n</code></pre></div>\n<aside class=\"version-note version-changed\" data-version=\"2.1\">\n<p class=\"version-note-title\">Changed in Django 2.1</p><p>Ordering and distinct support as described in the last two paragraphs was\nadded.</p>\n</aside>\n<p>When looking for which lookups are allowable after the <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> has been\napplied, Django uses the <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code> attribute. We didn't need to specify\nthis here as it didn't change, but supposing we were applying <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>\nto some field which represents a more complex type (for example a point\nrelative to an origin, or a complex number) then we may have wanted to specify\nthat the transform returns a <code class=\"docutils literal notranslate\"><span class=\"pre\">FloatField</span></code> type for further lookups. This can\nbe done by adding an <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code> attribute to the 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>This ensures that further lookups like <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lte</span></code> behave as they would for\na <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>Writing an efficient <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lt</span></code> lookup<a class=\"heading-anchor\" href=\"#writing-an-efficient-abs-lt-lookup\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>When using the above written <code class=\"docutils literal notranslate\"><span class=\"pre\">abs</span></code> lookup, the SQL produced will not use\nindexes efficiently in some cases. In particular, when we use\n<code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__lt=27</span></code>, this is equivalent to <code class=\"docutils literal notranslate\"><span class=\"pre\">change__gt=-27</span></code> AND\n<code class=\"docutils literal notranslate\"><span class=\"pre\">change__lt=27</span></code>. (For the <code class=\"docutils literal notranslate\"><span class=\"pre\">lte</span></code> case we could use the SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">BETWEEN</span></code>).</p>\n<p>So we would like <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> to generate\nthe following 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>実装は次のようになります。</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>There are a couple of notable things going on. First, <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code>\nisn't calling <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code>. Instead it skips the transformation of the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> done by <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> and uses the original <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code>. That is, we\nwant to get <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;experiments&quot;.&quot;change&quot;</span></code> not <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS(&quot;experiments&quot;.&quot;change&quot;)</span></code>.\nReferring directly to <code class=\"docutils literal notranslate\"><span class=\"pre\">self.lhs.lhs</span></code> is safe as <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code>\ncan be accessed only from the <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> lookup, that is the <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code>\nis always an instance of <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>.</p>\n<p>Notice also that  as both sides are used multiple times in the query the params\nneed to contain <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs_params</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs_params</span></code> multiple times.</p>\n<p>The final query does the inversion (<code class=\"docutils literal notranslate\"><span class=\"pre\">27</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">-27</span></code>) directly in the\ndatabase. The reason for doing this is that if the <code class=\"docutils literal notranslate\"><span class=\"pre\">self.rhs</span></code> is something else\nthan a plain integer value (for example an <code class=\"docutils literal notranslate\"><span class=\"pre\">F()</span></code> reference) we can't do the\ntransformations in Python.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">注釈</p>\n<p>In fact, most lookups with <code class=\"docutils literal notranslate\"><span class=\"pre\">__abs</span></code> could be implemented as range queries\nlike this, and on most database backends it is likely to be more sensible to\ndo so as you can make use of the indexes. However with PostgreSQL you may\nwant to add an index on <code class=\"docutils literal notranslate\"><span class=\"pre\">abs(change)</span></code> which would allow these queries to\nbe very efficient.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>双方向変換の例<a class=\"heading-anchor\" href=\"#a-bilateral-transformer-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> example we discussed previously is a transformation which\napplies to the left-hand side of the lookup. There may be some cases where you\nwant the transformation to be applied to both the left-hand side and the\nright-hand side. For instance, if you want to filter a queryset based on the\nequality of the left and right-hand side insensitively to some SQL function.</p>\n<p>Let's examine the simple example of case-insensitive transformation here. This\ntransformation isn't very useful in practice as Django already comes with a bunch\nof built-in case-insensitive lookups, but it will be a nice demonstration of\nbilateral transformations in a database-agnostic way.</p>\n<p>We define an <code class=\"docutils literal notranslate\"><span class=\"pre\">UpperCase</span></code> transformer which uses the SQL function <code class=\"docutils literal notranslate\"><span class=\"pre\">UPPER()</span></code> to\ntransform the values before comparison. We define\n<a class=\"reference internal\" href=\"/ja/2.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> to indicate that\nthis transformation should apply to both <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> and <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>Next, let's register it:</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>Now, the queryset <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__upper=&quot;doe&quot;)</span></code> will generate a case\ninsensitive query like this:</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>Writing alternative implementations for existing lookups<a class=\"heading-anchor\" href=\"#writing-alternative-implementations-for-existing-lookups\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Sometimes different database vendors require different SQL for the same\noperation. For this example we will rewrite a custom implementation for\nMySQL for the NotEqual operator. Instead of <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code> we will be using <code class=\"docutils literal notranslate\"><span class=\"pre\">!=</span></code>\noperator. (Note that in reality almost all databases support both, including\nall the official databases supported by Django).</p>\n<p>We can change the behavior on a specific backend by creating a subclass of\n<code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> with an <code class=\"docutils literal notranslate\"><span class=\"pre\">as_mysql</span></code> method:</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>We can then register it with <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>. It takes the place of the original\n<code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> class as it has the same <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>.</p>\n<p>When compiling a query, Django first looks for <code class=\"docutils literal notranslate\"><span class=\"pre\">as_%s</span> <span class=\"pre\">%</span> <span class=\"pre\">connection.vendor</span></code>\nmethods, and then falls back to <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. The vendor names for the in-built\nbackends are <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> and <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>Django がルックアップと変換のいずれを使うかを決定する仕組み<a class=\"heading-anchor\" href=\"#how-django-determines-the-lookups-and-transforms-which-are-used\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>In some cases you may wish to dynamically change which <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> or\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> is returned based on the name passed in, rather than fixing it. As\nan example, you could have a field which stores coordinates or an arbitrary\ndimension, and wish to allow a syntax like <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(coords__x7=4)</span></code> to return\nthe objects where the 7th coordinate has value 4. In order to do this, you\nwould override <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup</span></code> with something like:</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=\"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>You would then define <code class=\"docutils literal notranslate\"><span class=\"pre\">get_coordinate_lookup</span></code> appropriately to return a\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> subclass which handles the relevant value of <code class=\"docutils literal notranslate\"><span class=\"pre\">dimension</span></code>.</p>\n<p>There is a similarly named method called <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code>. <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup()</span></code>\nshould always return a <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> subclass, and <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code> a\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> subclass. It is important to remember that <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>\nobjects can be further filtered on, and <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> objects cannot.</p>\n<p>When filtering, if there is only one lookup name remaining to be resolved, we\nwill look for a <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. If there are multiple names, it will look for a\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. In the situation where there is only one name and a <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>\nis not found, we look for a <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> and then the <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> lookup on that\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. All call sequences always end with a <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. To clarify:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mylookup)</span></code> will call <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> will call\n<code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code>, and then\n<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> will first call\n<code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup('mytransform')</span></code>, which will fail, so it will fall back\nto calling <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code> and then\n<code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup('exact')</span></code>.</p></li>\n</ul>\n</section>","rootId":"custom-lookups","toc":[{"title":"シンプルなルックアップの例","anchor":"a-simple-lookup-example","children":[]},{"title":"シンプルな変換の例","anchor":"a-simple-transformer-example","children":[]},{"title":"Writing an efficient abs__lt lookup","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"双方向変換の例","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Writing alternative implementations for existing lookups","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Django がルックアップと変換のいずれを使うかを決定する仕組み","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"「How-to」ガイド","url":"/ja/2.1/howto/"}],"prev":{"docname":"howto/custom-model-fields","title":"カスタム model fieldsの実装","url":"/ja/2.1/howto/custom-model-fields/"},"next":{"docname":"howto/custom-template-tags","title":"独自のテンプレートタグとフィルタ","url":"/ja/2.1/howto/custom-template-tags/"},"formats":{"html":"/ja/2.1/howto/custom-lookups/","markdown":"/ja/2.1/howto/custom-lookups.md","json":"/ja/2.1/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/2.1.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/ja/2.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","pt-br","ko","es","el","pl"]}