{"title":"Penyesuaian Pencarian","version":"2.2","locale":"id","docname":"howto/custom-lookups","url":"/id/2.2/howto/custom-lookups/","canonical":"https://djangodocs.dev/id/2.2/howto/custom-lookups/","summary":"Django menawarkan beragam luas dari built-in lookups untuk penyaringan (sebagai contoh, exact dan icontains).","html":"<h1>Penyesuaian Pencarian<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 menawarkan beragam luas dari <a class=\"reference internal\" href=\"/id/2.2/ref/models/querysets/#field-lookups\"><span class=\"std std-ref\">built-in lookups</span></a> untuk penyaringan (sebagai contoh, <code class=\"docutils literal notranslate\">exact</code> dan <code class=\"docutils literal notranslate\">icontains</code>). Dokumentasi ini menjelaskan bagaimana menulis penyesuaian pencarian dan bagaimana mengubah pekerjaan dari pencarian yang ada. Untuk acuan API dari pencarian, lihat <a class=\"reference internal\" href=\"/id/2.2/ref/models/lookups/\"><span class=\"doc\">Lookup API reference</span></a>.</p>\n<section id=\"a-simple-lookup-example\">\n<h2>Sebuah contoh pencarian sederhana<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>Mari kita mulai dengan sebuah penyesuaian pencarian sederhana. Kami akan menulis penyesuaian pencarian <code class=\"docutils literal notranslate\">ne</code> yang bekerja berlawawan ke <code class=\"docutils literal notranslate\">exact</code>. <code class=\"docutils literal notranslate\">Author.objects.filter(name__ne='Jack')</code> akan dirubah ke 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>Backend SQL berdisi sendiri, sehingga kita tidak perlu khawatir tentang basisdata berbeda.</p>\n<p>Terdapat dua langkah untuk membuat ini bekerja. Pertama kami butuh menerapkan pencarian, kemudian kami butuh mengatakan Django tentang ini. Penerapannya sangat mudah:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Lookup\n\n<span class=\"k\">class</span> <span class=\"nc\">NotEqual</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s1\">&#39;ne&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_lhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params\n        <span class=\"k\">return</span> <span class=\"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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n</code></pre></div>\n<p>Untuk mendaftar pencarian <code class=\"docutils literal notranslate\">NotEqual</code> kami akan butuh memanggil <code class=\"docutils literal notranslate\">register_lookup</code> pada kelas bidang kami ingin pencarian menjadi tersedia. Dalam kasus ini, pencarian dapat dimengerti pada semua subkelas <code class=\"docutils literal notranslate\">Field</code>, jadi kami mendaftarkannya dengan <code class=\"docutils literal notranslate\">Field</code> secara langsung:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models.fields</span> <span class=\"kn\">import</span> Field\nField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>NotEqual<span class=\"p\">)</span>\n</code></pre></div>\n<p>Pendaftaran pencarian dapat juga dikerjakan menggunakan pola decorator:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models.fields</span> <span class=\"kn\">import</span> Field\n\n<span class=\"nd\">@Field</span><span class=\"o\">.</span>register_lookup\n<span class=\"k\">class</span> <span class=\"nc\">NotEqualLookup</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span>\n    <span class=\"c1\"># ...</span>\n</code></pre></div>\n<p>Kami sekarang dapat menggunakan <code class=\"docutils literal notranslate\">foo__ne</code> untuk setiap bidang <code class=\"docutils literal notranslate\">foo</code>. Anda akan butuh memastikan bahwa pendaftaran ini terjadi sebelum anda mencoba membuat kumpulan permintaan menggunakannya. Anda dapat menempatkan penerapan dalam sebuah berkas <code class=\"docutils literal notranslate\">models.py</code>, atau mendaftarkan pencarian dalam cara <code class=\"docutils literal notranslate\">ready()</code> dari sebuah <code class=\"docutils literal notranslate\">AppConfig</code>.</p>\n<p>Melihat lebih dekat pada penerapan, atribut dibutuhkan pertama adalah <code class=\"docutils literal notranslate\">lookup_name</code>. Ini mengizinkan ORM untuk memahami bagaimana mengartikan <code class=\"docutils literal notranslate\">name__ne</code> dan menggunakan <code class=\"docutils literal notranslate\">NotEqual</code> untuk membangkitkan SQL. Berdasarkan pemufakatan, nama-nama ini selalu deretan karakter huruf kecil mengandung hanya huruf, tetapi persyaratan mutlak adalah bahwa itu harus mengandung deretan karakter <code class=\"docutils literal notranslate\">__</code>.</p>\n<p>Kami lalu butuh menentukan cara <code class=\"docutils literal notranslate\">as_sql</code>. Ini mengambil obyek <code class=\"docutils literal notranslate\">SQLCompiler</code>, disebut <code class=\"docutils literal notranslate\">compiler</code>, dan hubungan aktif basisdata. Obyek <code class=\"docutils literal notranslate\">SQLCompiler</code> tidak didokumentasikan, tetapi satu-satunya kami butuh diketahui tentang mereka adalah bahwa mereka mempunyai cara <code class=\"docutils literal notranslate\">compile()</code> yang mengemblikan sebuah tuple mengandung deretan karakter SQL, dan parameter untuk disisipkan kedalam deretan karakter itu. Di kebanyakan kasus, anda tidak butuh menggunakannya secara langsung dan dapat melewatinya ke  <code class=\"docutils literal notranslate\">process_lhs()</code> dan <code class=\"docutils literal notranslate\">process_rhs()</code>.</p>\n<p>Sebuah <code class=\"docutils literal notranslate\">Lookup</code> bekerja terhadap dua nilai, <code class=\"docutils literal notranslate\">lhs</code> dan <code class=\"docutils literal notranslate\">rhs</code>, kepanjangan dari left-hand side dan right-hand side. Left-hand side biasanya acuan bidang, tetapi dia dapat menjadi apapun menerapkan <a class=\"reference internal\" href=\"/id/2.2/ref/models/lookups/#query-expression\"><span class=\"std std-ref\">query expression API</span></a>. Right-hand adalah nilai diberikan oleh pengguna. Dalam contoh <code class=\"docutils literal notranslate\">Author.objects.filter(name__ne='Jack')</code>, sisi tangan-kanan adalah sebuah acuan pada bidang <code class=\"docutils literal notranslate\">name</code> dari model <code class=\"docutils literal notranslate\">Author</code>, dan <code class=\"docutils literal notranslate\">'Jack'</code> adalah the right-hand side.</p>\n<p>Kami memanggil <code class=\"docutils literal notranslate\">process_lhs</code> dan <code class=\"docutils literal notranslate\">process_rhs</code> untuk merubah mereka kedalam nilai-nilai kami butuh untuk SQL menggunakan obyek <code class=\"docutils literal notranslate\">compiler</code> digambarkan sebelumnya. Cara ini mengembalikan tuple mengandung beberapa SQL dan parameter untuk ditambahkan kedaam SQL itu, seperti yang kita perlu untuk mengembalikan cara <code class=\"docutils literal notranslate\">as_sql</code> kami. Dalam contoh diatas, <code class=\"docutils literal notranslate\">process_lhs</code> mengembalikan <code class=\"docutils literal notranslate\">('&quot;author&quot;.&quot;name&quot;', [])</code> dan <code class=\"docutils literal notranslate\">process_rhs</code> mengembalikan <code class=\"docutils literal notranslate\">('&quot;%s&quot;', ['Jack'])</code>. Dalam contoh ini tidak ada parameter untuk left hand side, tetapi ini akan tergantung pada obyek kita punya, jadi jami masih butuh menyertakan merekan dalam parameter kami kembalikan.</p>\n<p>Akhirnya kami menggabungkan bagian-bagian kedalam sebuah pernyataan SQL dengan <code class=\"docutils literal notranslate\">&lt;&gt;</code>, dan memasok semua parameter untuk permintaan. Kami lalu mengambalikan sebuah tuple mengandung deretan karakter SQL dan parameter yang dibangkitkan.</p>\n</section>\n<section id=\"a-simple-transformer-example\">\n<h2>Contoh perubahan sederhana<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>Penyesuaian pencarian diatas adalah hebat, tetapi dalam beberapa kasus anda mungkin ingin dapat merangkai pencarian bersama-sama. Sebagai contoh, mari kita misalnya kami sedang membangun sebuah aplikasi dimana kami ingin membuat penggunaan dari operator <code class=\"docutils literal notranslate\">abs()</code>. Kami mempunyai sebuah model <code class=\"docutils literal notranslate\">Experiment</code> yang merekam sebuah nilai awal, nilai akhir, dan perubahan (awal - akhir). Kami akan suka menemukan semua percobaan dimana perubahan setara pada bilangan tertentu (<code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs=27)</code>), atau dimana itu tidak melebihi bilangan tertentu (<code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs__lt=27)</code>).</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Catatan</p>\n<p>Contoh ini agak dibikin, tetapi dia menunjukkan jangkauan fungsionalitas yang memungkinkan dalam cara backend basisdata berdisi sendiri, tanpa menggandakan fungsionalitas yang sudah ada di Django.</p>\n</aside>\n<p>Kami akan mulai dengan menulis sebuah perubahan <code class=\"docutils literal notranslate\">AbsoluteValue</code>. Ini akan menggunakan fungsi SQL <code class=\"docutils literal notranslate\">ABS()</code> untuk merubah nilai sebelum dibandingkan:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Transform\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s1\">&#39;abs&#39;</span>\n    function <span class=\"o\">=</span> <span class=\"s1\">&#39;ABS&#39;</span>\n</code></pre></div>\n<p>Selanjutnya, mari kita daftarkan sebagai <code class=\"docutils literal notranslate\">IntegerField</code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> IntegerField\nIntegerField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>AbsoluteValue<span class=\"p\">)</span>\n</code></pre></div>\n<p>Kami dapat sekarang menjalankan permintaan kami punyai sebelumnya. <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs=27)</code> akan membangkitkan SQL berikut:</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>SELECT <span class=\"o\">...</span> WHERE ABS<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>Dengan menggunakan <code class=\"docutils literal notranslate\">Transform</code> dari pada <code class=\"docutils literal notranslate\">Lookup</code> itu berarti kami dapat merangkai pencarian lebih lanjut setelahnya. Jadi <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs__lt=27)</code> akan membangkitkan SQL berikut:</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>SELECT <span class=\"o\">...</span> WHERE ABS<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>Catat bahwa dalam kasus terdapat tidak ada pencarian lain yang ditentukan, Django menterjemahkan <code class=\"docutils literal notranslate\">change__abs=27</code> sebagai <code class=\"docutils literal notranslate\">change__abs__exact=27</code>.</p>\n<p>Ini juga mengizinkan hasil digunakan dalam klausa <code class=\"docutils literal notranslate\">ORDER BY</code> dan <code class=\"docutils literal notranslate\">DISTINCT ON</code>. Sebagai contoh <code class=\"docutils literal notranslate\">Experiment.objects.order_by('change__abs')</code> membangkitkan:</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>SELECT <span class=\"o\">...</span> ORDER BY ABS<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> ASC\n</code></pre></div>\n<p>Dan pada basisdata yang mendukung perbedaan pada bidang (seperti PostgreSQL), <code class=\"docutils literal notranslate\">Experiment.objects.distinct('change__abs')</code> membangkitkan:</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>SELECT <span class=\"o\">...</span> DISTINCT ON ABS<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\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 2.1</p><p>Dukungan pengurutan dan pembedaan seperti digambarkan dalam dua paragraf terakhir telah ditambahkan.</p>\n</aside>\n<p>Ketika mencari pencarian mana yang diizinkan setelah <code class=\"docutils literal notranslate\">Transform</code> diberlakukan, Django menggunakan atribut <code class=\"docutils literal notranslate\">output_field</code>. Kami tidak butuh menentukan ini disini jika itu tidak berubah, tetapi seharusnya kami memberlakukan <code class=\"docutils literal notranslate\">AbsoluteValue</code> pada beberapa bidang yang mewakili jenis lebih rumit (sebagai contoh sebuah titik relatif ke yang asli, atau angka rumit) kemudian kami mungkin ingin menentukan bahwa perubahan mengembalikan jenis <code class=\"docutils literal notranslate\">FloatField</code> untuk pencarian lebih lanjut. Ini dapat dikerjakan dengan menambahkan sebuah atribut <code class=\"docutils literal notranslate\">output_field</code> untuk perubahan:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> FloatField<span class=\"p\">,</span> Transform\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s1\">&#39;abs&#39;</span>\n    function <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=\"nf\">output_field</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> FloatField<span class=\"p\">()</span>\n</code></pre></div>\n<p>Ini memastikan bahwa pencarian lebih lanjut seperti <code class=\"docutils literal notranslate\">abs__lte</code> berperilaku seperti mereka lakukan untuk <code class=\"docutils literal notranslate\">FloatField</code>.</p>\n</section>\n<section id=\"writing-an-efficient-abs-lt-lookup\">\n<h2>Menulis sebuah pencarian <code class=\"docutils literal notranslate\">abs__lt</code> efisien<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>Ketika menggunakan penulisan diatas pencarian <code class=\"docutils literal notranslate\">abs</code>, keluaran SQL tidak menggunakan indeks secara efisien dalam beberapa kasus. Khususnya, ketika kami menggunakan <code class=\"docutils literal notranslate\">change__abs__lt=27</code>, ini setara pada <code class=\"docutils literal notranslate\">change__gt=-27</code> AND <code class=\"docutils literal notranslate\">change__lt=27</code>. (Untuk kasus <code class=\"docutils literal notranslate\">lte</code> kami akan menggunakan SQL <code class=\"docutils literal notranslate\">BETWEEN</code>).</p>\n<p>Jadi kami akan <code class=\"docutils literal notranslate\">Experiment.objects.filter(change__abs__lt=27)</code> untuk membangkitkan SQL berikut:</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>SELECT <span class=\"o\">..</span> WHERE <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> AND <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>Peneprapannya adalah:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Lookup\n\n<span class=\"k\">class</span> <span class=\"nc\">AbsoluteValueLessThan</span><span class=\"p\">(</span>Lookup<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s1\">&#39;lt&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> compiler<span class=\"o\">.</span>compile<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>lhs<span class=\"o\">.</span>lhs<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params <span class=\"o\">+</span> lhs_params <span class=\"o\">+</span> rhs_params\n        <span class=\"k\">return</span> <span class=\"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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">,</span> lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n\nAbsoluteValue<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>AbsoluteValueLessThan<span class=\"p\">)</span>\n</code></pre></div>\n<p>Terdapat sepasang hal penting sedang terjadi. Pertama, <code class=\"docutils literal notranslate\">AbsoluteValueLessThan</code> tidak memanggil <code class=\"docutils literal notranslate\">process_lhs()</code>. Malahan dia melewati perubahan dari <code class=\"docutils literal notranslate\">lhs</code> dikerjakan oleh <code class=\"docutils literal notranslate\">AbsoluteValue</code> dan menggunakan <code class=\"docutils literal notranslate\">lhs</code> asli. Yaitu, kami ingin mendapatkan <code class=\"docutils literal notranslate\">&quot;experiments&quot;.&quot;change&quot;</code> bukan <code class=\"docutils literal notranslate\">ABS(&quot;experiments&quot;.&quot;change&quot;)</code>. Mengacu secara langsung pada <code class=\"docutils literal notranslate\">self.lhs.lhs</code> adalah aman <code class=\"docutils literal notranslate\">AbsoluteValueLessThan</code> dapat diakses hanya dari pencarian <code class=\"docutils literal notranslate\">AbsoluteValue</code>, yaitu <code class=\"docutils literal notranslate\">lhs</code> selalu sebuah instance dari <code class=\"docutils literal notranslate\">AbsoluteValue</code>.</p>\n<p>Perhaikan juga bahwa kedua sisi menggunakan banyak waktu dalam permintaan parameter butuh untuk dikandung <code class=\"docutils literal notranslate\">lhs_params</code> dan <code class=\"docutils literal notranslate\">rhs_params</code> banyak waktu.</p>\n<p>Permintaan akhir melakukan pembalikan (<code class=\"docutils literal notranslate\">27</code> ke <code class=\"docutils literal notranslate\">-27</code>) secara langsung di basisdata. Alasan untuk melakukan ini adalah bahwa jika <code class=\"docutils literal notranslate\">self.rhs</code> sesuatu lain daripada nilai integer polos (sebagai contoh sebuah acuan <code class=\"docutils literal notranslate\">F()</code>) kami tidak dapat melakukan perubahan dalam Python.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Catatan</p>\n<p>Faktanya, kebanyakan pencarian dengan <code class=\"docutils literal notranslate\">__abs</code> dapat diterapkan sebagai jangkauan permintaan seperti ini, dan pada kebanyakan backend basisdata sepertinya lebih bijaksana untuk dilakukan sehingga anda dapat membuat penggunaan indeks. Bagaimanapun dengan PostgreSQL anda mungkin ingin menambahkan indeks pada <code class=\"docutils literal notranslate\">abs(change)</code> yang akan mengizinkan permintaan ini menjadi lebih efisien.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>Sebuah contoh perubahan timbal balik<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>Contoh <code class=\"docutils literal notranslate\">AbsoluteValue</code> kami obrolkan sebelumnya adalah sebuah perubahan yang berlaku pada left-hand side dari pencarian. Mungkin disana beberapa kasus dimana anda ingin perubahan diberlakukan pada kedua left-hand side and the right-hand side. Sebagai contoh, jika anda ingin menyaring kumpulan permintaan berdasarkan pada persamaan left and right-hand side kebal pada beberapa fungsi SQL.</p>\n<p>Mari kita ujikan contoh sederhana dari perubahan kasus tidak peka disini. Perubahan ini tidak sangat berguna dalam praktiknya ketika Django sudah datang dengan seikat pencarian siap pakai tidak peka, tetapi dia akan menjadi pertunjukan bagus dari perubahan timbal balik dalam sebuah cara basisdata-agnostik.</p>\n<p>Kami menentukan sebuab perubahan UpperCase` yang menggunakan fungsi SQL <code class=\"docutils literal notranslate\">UPPER()</code> untuk merubah nilai sebelum dibandingkan. Kami menentukan <a class=\"reference internal\" href=\"/id/2.2/ref/models/lookups/#django.db.models.Transform.bilateral\" title=\"django.db.models.Transform.bilateral\"><code class=\"xref py py-attr docutils literal notranslate\">bilateral = True</code></a> untuk mengindikasikan bahwa perubahan ini harus berlaku pada kedua <code class=\"docutils literal notranslate\">lhs</code> and <code class=\"docutils literal notranslate\">rhs</code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> Transform\n\n<span class=\"k\">class</span> <span class=\"nc\">UpperCase</span><span class=\"p\">(</span>Transform<span class=\"p\">):</span>\n    lookup_name <span class=\"o\">=</span> <span class=\"s1\">&#39;upper&#39;</span>\n    function <span class=\"o\">=</span> <span class=\"s1\">&#39;UPPER&#39;</span>\n    bilateral <span class=\"o\">=</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>Selanjutnya, mari kita mendaftarkannya:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db.models</span> <span class=\"kn\">import</span> CharField<span class=\"p\">,</span> TextField\nCharField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>UpperCase<span class=\"p\">)</span>\nTextField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>UpperCase<span class=\"p\">)</span>\n</code></pre></div>\n<p>Sekarang, kumpulan permintaan <code class=\"docutils literal notranslate\">Author.objects.filter(name__upper=&quot;doe&quot;)</code> akan membangkitkan sebuah permintaan kasus tidak peka seperti ini:</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>SELECT <span class=\"o\">...</span> WHERE UPPER<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> UPPER<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>Menulis penerapan cara lain untuk pencarian yang ada<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>Terkadang penjaja basisdata berbeda membutuhkan SQL berbeda untuk pekerjaan yang sama. Untuk contoh ini kami akan menulis kembali sebuah penyesuaian penerapan untuk MySQL untuk penghubung NotEqual. Dari pada <code class=\"docutils literal notranslate\">&lt;&gt;</code> kami akan menggunakan penghubung <code class=\"docutils literal notranslate\">!=</code>. (Catat bahwa dalam kenyataan hampir semua basisdata mendukung keduanya, termasuk semua basisdata resmi didukung oleh Django).</p>\n<p>Kami dapat merubah perilaku pada backend khusus dengan membuat subkelas dari <code class=\"docutils literal notranslate\">NotEqual</code> dengan sebuah metode <code class=\"docutils literal notranslate\">as_mysql</code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">MySQLNotEqual</span><span class=\"p\">(</span>NotEqual<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">as_mysql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> compiler<span class=\"p\">,</span> connection<span class=\"p\">,</span> <span class=\"o\">**</span>extra_context<span class=\"p\">):</span>\n        lhs<span class=\"p\">,</span> lhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_lhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        rhs<span class=\"p\">,</span> rhs_params <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>process_rhs<span class=\"p\">(</span>compiler<span class=\"p\">,</span> connection<span class=\"p\">)</span>\n        params <span class=\"o\">=</span> lhs_params <span class=\"o\">+</span> rhs_params\n        <span class=\"k\">return</span> <span class=\"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>lhs<span class=\"p\">,</span> rhs<span class=\"p\">),</span> params\n\nField<span class=\"o\">.</span>register_lookup<span class=\"p\">(</span>MySQLNotEqual<span class=\"p\">)</span>\n</code></pre></div>\n<p>Kami dapat mendaftarkannya dengan <code class=\"docutils literal notranslate\">Field</code>. Dia memakan tempat dari kelas <code class=\"docutils literal notranslate\">NotEqual</code> asli seperti dia mempunyai <code class=\"docutils literal notranslate\">lookup_name</code> sama.</p>\n<p>Ketika menyusun sebuah permintaan, Django pertama mencari cara <code class=\"docutils literal notranslate\">as_%s % connection.vendor</code>, dan kemudian kembali ke <code class=\"docutils literal notranslate\">as_sql</code>. Nama penjaja untuk membangun backend adalah <code class=\"docutils literal notranslate\">sqlite</code>, <code class=\"docutils literal notranslate\">postgresql</code>, <code class=\"docutils literal notranslate\">oracle</code> dan <code class=\"docutils literal notranslate\">mysql</code>.</p>\n</section>\n<section id=\"how-django-determines-the-lookups-and-transforms-which-are-used\">\n<h2>Bagaimana Django menentuka pencarian dan merubah yang sedang digunakan<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>Dalam beberapa kasus anda mungkin berharap untuk secara dinamis merubah <code class=\"docutils literal notranslate\">Transform</code> atau <code class=\"docutils literal notranslate\">Lookup</code> dikembalikan berdasarkan pada nama dilewatkan, daripada memperbaikinya. Sebagai sebuah contoh, anda dapat mempunyai sebuah bidang yang menyimpan kordinat atau dimensi berubah-ubah dan berharap untuk mengizinkan sebuah sintaksis seperti <code class=\"docutils literal notranslate\">.filter(coords__x7=4)</code> untuk mengembalikan obyek dimana kordinat 7 mempunyai nilai 4. Untuk melakukan ini, anda akan menimpa  <code class=\"docutils literal notranslate\">get_lookup</code> dengan sesuatu seperti:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">CoordinatesField</span><span class=\"p\">(</span>Field<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_lookup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> lookup_name<span class=\"p\">):</span>\n        <span class=\"k\">if</span> lookup_name<span class=\"o\">.</span>startswith<span class=\"p\">(</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">):</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                dimension <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span>lookup_name<span class=\"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> get_coordinate_lookup<span class=\"p\">(</span>dimension<span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>get_lookup<span class=\"p\">(</span>lookup_name<span class=\"p\">)</span>\n</code></pre></div>\n<p>Anda kemudian akan menentukan <code class=\"docutils literal notranslate\">get_coordinate_lookup</code> dengan benar untuk mengembalikan sebuah subkelas <code class=\"docutils literal notranslate\">Lookup</code> yang menangani nilai yang terkait dari <code class=\"docutils literal notranslate\">dimension</code>.</p>\n<p>Ada cara yang dinamai mirip dipanggil <code class=\"docutils literal notranslate\">get_transform()</code>. <code class=\"docutils literal notranslate\">get_lookup()</code> harus selalu mengembalikan sebuah subkelas <code class=\"docutils literal notranslate\">Lookup</code>, dan <code class=\"docutils literal notranslate\">Lookup</code> sebuah subkelas <code class=\"docutils literal notranslate\">Transform</code>. Itu sangat penting diingat bahwa obyek <code class=\"docutils literal notranslate\">Transform</code> dapat lebih jauh disaring, dan obyek <code class=\"docutils literal notranslate\">Lookup</code> tidak dapat.</p>\n<p>Ketika menyaring, jika hanya ada satu nama pencarian tersisa untuk diselesaikan, kami akan mencari sebuah <code class=\"docutils literal notranslate\">Lookup</code>. Jika ada banyak nama, dia akan mencari sebuah <code class=\"docutils literal notranslate\">Transform</code>. Dalam keadaan dimana hanya ada satu nama dan sebuah <code class=\"docutils literal notranslate\">Lookup</code> tidak ditemukan, kami mencari sebuah <code class=\"docutils literal notranslate\">Transform</code> dan kemudian pencarian <code class=\"docutils literal notranslate\">exact</code> pada <code class=\"docutils literal notranslate\">Transform</code> tersebut. Semua panggilan selalu berurutan diakhiri dengan sebuah <code class=\"docutils literal notranslate\">Lookup</code>. Untuk menjelaskan:</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mylookup)</code> akan memanggil <code class=\"docutils literal notranslate\">myfield.get_lookup('mylookup')</code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mytransform__mylookup)</code> akan memanggil <code class=\"docutils literal notranslate\">myfield.get_transform('mytransform')</code>, dan lalu <code class=\"docutils literal notranslate\">mytransform.get_lookup('mylookup')</code>.</p></li>\n<li><p><code class=\"docutils literal notranslate\">.filter(myfield__mytransform)</code> akan memanggil pertama <code class=\"docutils literal notranslate\">myfield.get_lookup('mytransform')</code>, yang akan gagal, sehingga dia akan gagal kembali memanggil <code class=\"docutils literal notranslate\">myfield.get_transform('mytransform')</code> dan kemudian <code class=\"docutils literal notranslate\">mytransform.get_lookup('exact')</code>.</p></li>\n</ul>\n</section>","rootId":"custom-lookups","toc":[{"title":"Sebuah contoh pencarian sederhana","anchor":"a-simple-lookup-example","children":[]},{"title":"Contoh perubahan sederhana","anchor":"a-simple-transformer-example","children":[]},{"title":"Menulis sebuah pencarian abs__lt efisien","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"Sebuah contoh perubahan timbal balik","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Menulis penerapan cara lain untuk pencarian yang ada","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Bagaimana Django menentuka pencarian dan merubah yang sedang digunakan","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"Panduan \"Bagaimana\"","url":"/id/2.2/howto/"}],"prev":{"docname":"howto/custom-model-fields","title":"Menulis bidang model penyesuaian","url":"/id/2.2/howto/custom-model-fields/"},"next":{"docname":"howto/custom-template-tags","title":"Penyesuaian etiket cetakan dan saringan","url":"/id/2.2/howto/custom-template-tags/"},"formats":{"html":"/id/2.2/howto/custom-lookups/","markdown":"/id/2.2/howto/custom-lookups.md","json":"/id/2.2/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/2.2.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/id/2.2/howto/custom-lookups/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}