Ihfazhillahhttps://blog.ihfazh.com/2024-02-10T13:25:00+07:00Child Daily Track Privacy Policy2024-02-10T13:25:00+07:002024-02-10T13:25:00+07:00Ihfazhillahtag:blog.ihfazh.com,2024-02-10:/child-daily-track-privacy-policy.html<p>Child Daily Track Privacy Policy</p><p><strong>Privacy Policy</strong></p>
<p>Muhammad Ihfazhillah built the Child Daily Track app as an Open Source app. This SERVICE is provided by Muhammad Ihfazhillah at no cost and is intended for use as is.</p>
<p>This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.</p>
<p>If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.</p>
<p>The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which are accessible at Child Daily Track unless otherwise defined in this Privacy Policy.</p>
<p><strong>Information Collection and Use</strong></p>
<p>For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information, including but not limited to Username, photo, video, gallery. The information that I request will be retained on your device and is not collected by me in any way.</p>
<p>The app does use third-party services that may collect information used to identify you.</p>
<p>Link to the privacy policy of third-party service providers used by the app</p>
<ul>
<li><a href="https://www.google.com/policies/privacy/">Google Play Services</a></li>
<li><a href="https://sentry.io/privacy/">Sentry</a></li>
</ul>
<p><strong>Log Data</strong></p>
<p>I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third-party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.</p>
<p><strong>Cookies</strong></p>
<p>Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.</p>
<p>This Service does not use these “cookies” explicitly. However, the app may use third-party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.</p>
<p><strong>Service Providers</strong></p>
<p>I may employ third-party companies and individuals due to the following reasons:</p>
<ul>
<li>To facilitate our Service;</li>
<li>To provide the Service on our behalf;</li>
<li>To perform Service-related services; or</li>
<li>To assist us in analyzing how our Service is used.</li>
</ul>
<p>I want to inform users of this Service that these third parties have access to their Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.</p>
<p><strong>Security</strong></p>
<p>I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.</p>
<p><strong>Links to Other Sites</strong></p>
<p>This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.</p>
<p><strong>Children’s Privacy</strong></p>
<p>These services address anyone under the age of 13. This application used to track task of your given task into them, and may let you confirm their work by sending their video of activity.</p>
<p><strong>Changes to This Privacy Policy</strong></p>
<p>I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page.</p>
<p>This policy is effective as of 2024-02-10</p>
<p><strong>Contact Us</strong></p>
<p>If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at mihfazhillah@gmail.com.</p>
<p>This privacy policy page was created at <a href="https://privacypolicytemplate.net">privacypolicytemplate.net</a> and modified/generated by <a href="https://app-privacy-policy-generator.nisrulz.com/">App Privacy Policy Generator</a></p>[Micropython 6] Mengatur Kecerahan LED Menggunakan PWM2023-09-23T21:49:00+07:002023-09-23T21:49:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-09-23:/micropython-6-mengatur-kecerahan-led-menggunakan-pwm.html<p>Bagaimana mengatur kecerahan LED secara terprogram menggunakan micropython? Kamu bisa menggunakan PWM. Pulse Width Modulation. Simak lebih lengkapnya di seri ini.</p><p><img alt="Duty Cycle" src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Duty_Cycle_Examples.png">
By Thewrightstuff - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=72876123</p>
<h1>Bismillah</h1>
<p>Pernah menemui lampu kamar yang bisa diatur kecerahannya dengan memutar saklar putar yang tertempel di tembok? Kamu bisa melakukan hal tersebut menggunakan raspberry pi pico kamu menggunakan PWM. Pulse Width Modulation.</p>
<p>Dengan PWM ini, kamu bisa mengontrol presentase kecerahan LED dari 0% sampai 100%.</p>
<p>Seperti biasa, asumsi saya kamu telah membeli paket <a href="https://tokopedia.link/mY83NSZNHCb">Get Started With Micropython In Raspberry Pi Pico</a> karena semua yang kita butuhkan di seri seri awal ini ada disana semua. Bila tidak, maka berikut beberapa alat yang kamu perlukan:</p>
<ol>
<li><a href="https://tokopedia.link/QkgWSqRYICb">Breadboard</a></li>
<li><a href="https://tokopedia.link/Rq0eCOYYICb">Raspberry pi pico</a></li>
<li><a href="https://tokopedia.link/Yjn7jjfZICb">LED</a></li>
<li><a href="https://tokopedia.link/jB7zBp2YICb">Resistor 330 Ohm</a></li>
<li>Kabel data micro usb</li>
<li>Beberapa kabel jumper male to male</li>
</ol>
<h3>Skema</h3>
<p>Kamu bisa menggunakan skema untuk LED pada <a href="https://blog.ihfazh.com/micropython-4-mengontrol-external-led-menggunakan-push-button">seri ke 4</a>. Asumsi saya kamu menggunakan skema persis pada <a href="https://blog.ihfazh.com/micropython-4-mengontrol-external-led-menggunakan-push-button">seri ke 4</a> ini, yaitu menggunakan pin 16 untuk mengontrol LED kamu.</p>
<h3>Kode</h3>
<p>Tulis kode dibawah ini dan simpan menggunakan nama <code>pwm_dasar.py</code>. </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span><span class="p">,</span> <span class="n">PWM</span>
<span class="n">red</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span>
<span class="n">pwm</span> <span class="o">=</span> <span class="n">PWM</span><span class="p">(</span><span class="n">red</span><span class="p">)</span>
<span class="n">pwm</span><span class="o">.</span><span class="n">freq</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
<span class="n">pwm</span><span class="o">.</span><span class="n">duty_u16</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="mi">30</span><span class="o">/</span><span class="mi">100</span> <span class="o">*</span> <span class="mi">65535</span><span class="p">))</span>
</code></pre></div>
<p>Jalankan dengan <code>mpremote run pwm_dasar.py</code></p>
<h3>Penjelasan</h3>
<p>Seperti biasa, diawal kita meng-import library yang kita butuhkan. Kita butuh <code>Pin</code> karena dengan itu kita
mendefinisikan dimana LED kita terkoneksikan.</p>
<p>Kita juga membutuhkan modul PWM untuk mengatur kecerahan LED pada pin tersebut.</p>
<p>Perhatikan <code>pwm = PWM(led)</code>. <code>PWM</code> ini menerima Pin object sebagai parameter, bukan angka atau string untuk ID suatu Pin. Ini berarti, kita akan menggunakan modul pwm untuk mengatur kecerahan LED.</p>
<p>Kemudian kita mengatur frekuensi pada <code>pwm.freq(200)</code></p>
<p>Pada akhirnya, kita mengatur kecerahan LED menggunakan <code>pwm.duty_u16</code> untuk sekitar kecerahan 30% dari total kecerahan LED. Karena fungsi <code>duty_u16</code> membutuhkan integer, maka kita perlu mengkonversi nilai pecahan menjadi integer menggunakan fungsi <code>int</code>.</p>
<h3>PWM</h3>
<p>PWM adalah sebuah metode yang berguna untuk mengontrol daya rata rata yang akan dikirimkan ke beban. Dalam hal ini, beban kita adalah LED. Dan pada contoh kode diatas, daya rata rata yang kita inginkan adalah 30%.</p>
<p>Cara untuk memberikan daya rata rata tersebut adalah dengan menyala matikan beban dengan kecepatan lebih cepat daripada yang dibutuhkan oleh beban. Semakin lama matinya, semakin redup. Sebaliknya, semakin lama menyala, semakin terang.</p>
<p>Di kode sebelumnya, kamu mengatur frekuensi dengan menggunakan method <code>freq</code>. Frekuensi ini adalah berapa kali beban nyala dan mati dalam satu detik. Satuannya adalah Hertz. Untuk mengatur LED, 100 - 120 Hz sudah cukup.</p>
<p>Adapun <strong>duty</strong> adalah jarak lama antara hidup dan mati. Jadi dalam rentang 100 kali per detik itu, berapa lama perbandingan antara hidupnya beban dan matinya beban.</p>
<p><img alt="" src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Duty_Cycle_Examples.png">
By Thewrightstuff - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=72876123</p>
<p>Untuk di micropython sendiri kamu bisa mengatur duty menggunakan <code>duty_u16</code> atau <code>duty_ns</code>. Yang pertama menggunakan rentang 0 - 65535. Sedangkan yang kedua menggunakan satuan nano seconds. </p>
<p>Untuk membuktikan bahwa PWM itu adalah siklus antara nyala dan mati dari suatu pin, maka kamu bisa mengecilkan frekuensi menjadi 10. Kamu akan lihat bahwa LED berkedip dengan kecerahan 100%. </p>
<h3>Penutup</h3>
<p>Nah itu dia tentang PWM. Kamu bisa mengatur kecerahan LED menggunakan PWM. Kamu juga sudah belajar tentang cara kerja PWM, frekuensi dan duty. Selain untuk mengatur kecerahan LED, PWM ini biasa digunakan untuk mengatur kecepatan dinamo motor, dan juga dipakai dalam Solar Charger Controller.</p>
<p>Kamu juga bisa menggabungkan dengan <a href="https://blog.ihfazh.com/micropython-5-membaca-potentio-meter-menggunakan-micropython">seri sebelumnya</a>. Mendapatkan presentase menggunakan potentiometer, dan mengatur kecerahan menggunakan kembalian potentiometer tersebut ke led. </p>
<p>Selamat mencoba.</p>[Micropython 5] Membaca Potentiometer Menggunakan Micropython2023-09-15T21:09:00+07:002023-09-15T21:09:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-09-15:/micropython-5-membaca-potentio-meter-menggunakan-micropython.html<p>Selain kita bisa membaca on dan off dari suatu pin, kita juga bisa membaca value selain on dan off. Misal kita ingin mengetahui berapa voltase baterai yang sedang kita gunakan. Atau seberapa putaran potentiometer sehingga kita bisa tahu berapa volumenya. Semuanya menjadi mungkin menggunakan program yang bernama ADC. Analog to Digital Converter.</p><p><a href="https://tokopedia.link/Oc4i60jo8Cb"><img alt="Potentio" src="https://blog.ihfazh.com/images/potentio.jpeg"></a></p>
<h1>Bismillah</h1>
<p>Potentiometer adalah pegangan yang biasa kita putar ketika mengatur suatu volume. Atau semacam pegangan di motor bagian kanan untuk mengatur gas. </p>
<p>Di seri ini, kita akan mempelajari bagaimana menggunakan ADC Analog to Digital Converter yang bisa kita gunakan untuk membaca value dari potentiometer.</p>
<p>Seperti biasa, asumsi saya kamu telah membeli paket <a href="https://tokopedia.link/mY83NSZNHCb">Get Started With Micropython In Raspberry Pi Pico</a> karena semua yang kita butuhkan di seri seri awal ini ada disana semua. Bila tidak, maka berikut beberapa alat yang kamu perlukan:</p>
<ol>
<li><a href="https://tokopedia.link/QkgWSqRYICb">Breadboard</a></li>
<li><a href="https://tokopedia.link/Rq0eCOYYICb">Raspberry pi pico</a></li>
<li><a href="https://tokopedia.link/Oc4i60jo8Cb">Potentiometer 10K</a></li>
<li>Kabel data micro usb</li>
<li>Beberapa kabel jumper male to male</li>
</ol>
<h3>ADC</h3>
<p>Di seri-seri sebelumnya, kita hanya bisa membaca on off dari push button. Itu adalah representasi dari high dan low, atau 1 dan 0. Lalu, bagaimana dengan membaca suara, temperature, voltase baterai atau hal hal lain yang hasil keluarannya tidak hanya 1 dan 0?</p>
<p>Dengan fitur ADC yang tertanam di raspberry pi pico, kita bisa melakukan itu semua. Raspberry pi pico menggunakan resolusi 12-bit untuk ADC-nya. Sehingga rentang angka yang akan kamu dapatkan ketika membaca dari Pin khusus ADC adalah 0 - 4095.</p>
<p>Namun di micropython, semua boards diseragamkan untuk menggunakan resolusi 16-bit. Sehingga kamu akan mendapatkan angka pada rentang 0 - 65535.</p>
<p>Pin ADC yang tersedia untuk kita pakai ada 3. <strong>Pin 26, 27 dan 28</strong>.</p>
<p><img alt="Pinout ADC" src="https://blog.ihfazh.com/images/pinout-adc.png">
Lihat https://pico.pinout.xyz/</p>
<h3>Potentiometer</h3>
<p><a href="https://tokopedia.link/QCvnrqp28Cb"><img alt="Potentio Meter" src="https://www.olelectronics.in/wp-content/uploads/Metal-Potentiometer-4.jpg"></a>
Gambar dari https://www.olelectronics.in/product/10k-potentiometer-metal/</p>
<p>Potentiometer ini memiliki 3 kaki. Kaki tengah adalah kaki yang perlu kamu hubungkan ke salah satu Pin yang khusus untuk ADC tadi. Bisa 26, 27 atau 28. Adapun kaki kanan dan kirinya, salah satu kamu masukkan ke pin power 3.3v, dan satunya hubungkan ke pin ground. </p>
<p>Tidak masalah terbalik, dia hanya menentukan arah putarannya. </p>
<h3>Kode</h3>
<p>Ketikkan kode berikut dan simpan dengan nama <code>potentio.py</code></p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">ADC</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">potentio</span> <span class="o">=</span> <span class="n">ADC</span><span class="p">(</span><span class="mi">26</span><span class="p">)</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Value sekarang adalah: </span><span class="si">{</span><span class="n">potentio</span><span class="o">.</span><span class="n">read_16</span><span class="p">()</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<p>Pertama kita definisikan variable <code>potentio</code> ke <code>ADC(26)</code> karena kita hubungkan kaki tengah ke pin 26. Bila kamu menghubungkan ke pin lainnya, ubah angka pin tersebut.</p>
<p>Lalu di <code>while loop</code> kita baca value potentio menggunakan method <code>read_16()</code></p>
<p>Jalankan dengan <code>mpremote run potentio.py</code> dan lihat hasilnya di console.</p>
<p>Kamu akan dapati bahwa angka akan berubah ubah dari besar ke kecil atau sebaliknya ketika kita memutar potentionya.</p>
<p>Kalau sudah, coba balik antara positif dan ground nya kemudian putar putar potentionya. Kamu akan dapati bahwa perubahan dari besar ke kecil atau sebaliknya akan terbalik.</p>
<h3>Mendapatkan voltase keluaran</h3>
<p>Mari berhitung sejenak. </p>
<p>Bila keluaran dari potentio adalah mendekati 0, maka kita anggap 0v. Bila keluaran dari potentio mendekati 65535, maka kita anggap voltasenya adalah 3.3v.</p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0</span>
<span class="mf">3.3</span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">65535</span>
<span class="err">?</span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">50000</span>
</code></pre></div>
<p>Kita cari pengalinya dengan rumus <code>3.3 / 65535</code></p>
<p>Lalu hasil pengali tersebut kita gunakan untuk mengalikan <code>50000</code>. Akhirnya kita dapatkan voltase akhirnya. </p>
<p>Kemudian kita ubah logika diatas menjadi kode berikut ini:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">ADC</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">potentio</span> <span class="o">=</span> <span class="n">ADC</span><span class="p">(</span><span class="mi">26</span><span class="p">)</span>
<span class="n">pengali</span> <span class="o">=</span> <span class="mf">3.3</span> <span class="o">/</span> <span class="mi">65535</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Voltase sekarang adalah: </span><span class="si">{</span><span class="n">potentio</span><span class="o">.</span><span class="n">read_16</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">pengali</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<h3>Penutup</h3>
<p>Nah itu dia berkaitan dengan ADC. Di raspberry pi pico, kamu hanya bisa menggunakan 3 Pin untuk keperluan ini, 26, 27 dan 28.</p>
<p>Kamu bisa menggunakan ADC untuk mengukur suhu, membaca potentiometer, mengukur voltase suatu baterai, dan lain sebagainya.</p>
<p>Sampai bertemu di seri selanjutnya. Kita akan menggabungkan konsep ini dengan mengatur terang gelapnya LED insyaAlloh di seri selanjutnya.</p>Pakan Lele Organik Otomatis2023-09-10T09:12:00+07:002023-09-10T09:12:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-09-10:/pakan-lele-organik-otomatis.html<p>Cerita tentang otomatisasi pemberian pakan lele organik</p><h1>Bismillah</h1>
<p>Beberapa bulan ini, saya sedang explore berkaitan dengan otomatisasi pemberian pakan ikan. Karena yang terbiasa adalah pakan berbentuk pelet, hint pertama yang ada dikepala saya adalah, mencari auto fish feeder dan mempelajari alurnya.</p>
<p>Okay, sudah banyak tutorial baik yang sederhana menggunakan servo murah dan botol bekas, atau pakai gentong pakai dinamo dan pelempar pakan, atau bahkan 3d printing. Banyak.</p>
<p>Setelah cerita dan berkonsultasi sama tetangga, dapat konsep yang bernama Taga, kepanjangan dari Tanpa airator dan ganti air dari <a href="https://www.indonetwork.co.id/product/joyo-farm-probiotik-7098105">Joyo Farm</a>. </p>
<p>Inti dari konsepnya adalah untuk meminimalisir pergantian air (zero water excange), mengurangi jumlah penggunaan pelet (kalau mau hybrid yah), dan mengurangi penggunaan airator.</p>
<p>Btw, saya disini tidak banyak bahas masalah konsep ini yah. Karena basic saya di software yang nyemplung dikit dikit di hardware (bisa jadi nantinya nyemplung banyak), maka saya fokus di "otomatisasi". Kalau mau tanya tanya lebih lanjut, silahkan hubungi <a href="https://www.indonetwork.co.id/product/joyo-farm-probiotik-7098105">Joyo Farm</a> secara langsung.</p>
<h3>Pemberian pakan</h3>
<p>Setelah saya konsultasi, ternyata pemberian pakannya bukan pakan apung. Sehingga pencarian saya sebelumnya tidak terpakai disini.</p>
<p>Pakan berbentuk semacam lumpur, kita aduk dahulu, kemudian kita berikan ke kolam, dan masukkan air lagi ke lumbung pakannya.</p>
<p>Pemberian pakan adalah 3 kali sehari, jam 8, jam 16 dan jam 22. </p>
<p>Kita akan otomatisasi itu semua. </p>
<h3>Solusi</h3>
<p>Setelah melakukan "experiment" kecil kecilan, akhirnya saya membuat alur versi pertama seperti ini:</p>
<ol>
<li>alat mengaduk pakan dalam gentong</li>
<li>air masuk kedalam gentong dengan bantuan pompa, sehingga membuat dorongan untuk mengeluarkan air melalui lobang yang dipersiapkan.</li>
</ol>
<p>Air yang keluar tersebut sudah tercampur dengan pakan yang sudah kita aduk tadi.</p>
<p>Berikut hasilnya</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/lojRU8Jl6Eg?si=ftF74Oy2zYEWHi8q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h3>Kesimpulan</h3>
<p>Banyak kekurangan? Ya betul. Tapi dengan menjalaninya, hampir tiap hari saya dan istri mendapatkan ide ide baru, untuk menjadikan alat ini lebih efisien dan benar benar mentransfer pakan ke lele, tidak hanya air yang bersirkulasi.</p>
<p>Beberapa hal yang akan kami update untuk versi kedua:</p>
<ol>
<li>Mixer dan Dinamo yang akan kita update</li>
<li>Daripada harus membuat tekanan, kenapa tidak kita keluarkan dari samping gentong? Sehingga tidak ada tekanan air ketutupnya dan meminimalisir air keluar sia sia.</li>
</ol>
<p>2 hal ini adalah mayor manurut saya untuk dilakukan explorasi, terutama yang pertama. Sehingga pakan itu bener bener sampai ke lele, dan tidak mengendap di bawah dan mengeras.</p>
<p>Saat ini fokusnya adalah otomatisasi, jadi jangan tanya dulu perkembangannya.</p>
<h3>Apa yang kita pelajari?</h3>
<p>Banyak, diantaranya:</p>
<ol>
<li>Raspberry pi pico dan micropython. Oleh sebab inilah saya menulis seri berkaitan micropython dan raspberry pi pico. </li>
<li>Elektronika. Ya saya belajar solder menyolder, memahami alur tiap komponen, melakukan perhitungan, dan juga pembuatan PCB. Kamu tahu, v1 pertama ini saya menggunakan PCB lobang satu sisi dan banyak kabel yang lalu lalang :D. </li>
<li>Konsep Dinamo dan hubungan antara torsi dan rpm.</li>
<li>Konsep pergiran. Bagaimana membagi beban sehingga dengan dinamo tamiya bisa mengangkat beban lebih dari 30kg.</li>
<li>Pertukangan, design 3d, bubut dsb...</li>
</ol>
<p>Kita pelajari apa yang kita butuhkan saja, belum tentu saya bisa menjelaskan semua tentang itu semua</p>
<h3>Barang yang saya pergunakan?</h3>
<ol>
<li><a href="https://tokopedia.link/TC3ORrV8XCb">Raspberry pi pico wifi</a></li>
<li><a href="https://tokopedia.link/1y64Xc58XCb">PCB bolong satu sisi</a></li>
<li><a href="https://tokopedia.link/MjyrNL88XCb">Relay 8 channel</a> (kebanyakan untuk versi ini)</li>
<li><a href="https://tokopedia.link/a6UZVNy9XCb">Motor DC 12v 200RPM 1.2KGfCM</a></li>
<li><a href="https://www.tokopedia.com/mollarofficial/mollar-pp25w-pompa-air-dc-12-volt-push-pump-12v-25-watt?extParam=ivf%3Dfalse%26whid%3D8985&src=topads">Pompa DC</a></li>
<li>Perselangan</li>
<li><a href="https://tokopedia.link/uFXohPQ9XCb">Step Down</a>: Saya gunakan untuk menurunkan tegangan baterai dari 12v ke 5v. Untuk power raspberry pi dan relaynya.</li>
<li><a href="https://tokopedia.link/Rns3zwA9XCb">Aki atau baterai 12v</a></li>
<li>Resistor. Saya gunakan ini untuk membagi tegangan aki 12v supaya bisa saya baca tegangan akinya dari raspberry pi pico</li>
<li><a href="https://tokopedia.link/LKS5m6C9XCb">Solar Panel</a>. Saran saya, jangan lupa beli SCC dan juga kabel konektornya juga di <a href="https://tokopedia.link/h1VsQmG9XCb">toko yang sama</a>. Supaya tidak bolak balik pesen dan double ongkir jadinya selain harus menunggu lebih lama.</li>
<li><a href="https://www.tokopedia.com/tokohoki7/drum-plastik-ember-plastik-tong-plastik-tong-hdpe-kap-30l-tebal-kuat?extParam=ivf%3Dfalse%26src%3Dsearch&refined=true">Gentong bekas 30L beserta klemnya</a></li>
<li>Potongan kawat 2mm dari mixer dapur.</li>
<li>Tidak lupa kolam 1mx1mx1m (bisa check check <a href="https://tokopedia.link/GNXyVkaaYCb">di sini</a> atau cari di kota kamu) dan lele serta pakan organiknya.</li>
</ol>
<h3>Kode?</h3>
<p>Adapun kodenya, untuk versi sekarang ada 2 layer:</p>
<ol>
<li><a href="https://github.com/ihfazhillah/ksatriamuslim_backend/tree/main/ksatria_muslim/irrigation">backend</a>, dan saya tumpangkan di web ksatriamuslim, kode bisa dilihat <a href="https://github.com/ihfazhillah/ksatriamuslim_backend/tree/main/ksatria_muslim/irrigation">di folder ini</a></li>
<li><a href="https://github.com/ihfazhillah/irigation-system/blob/main/irrigation_new_main.py">micropython</a>, program untuk otomatisasi di <a href="https://tokopedia.link/JC2CFLDaYCb">board raspberrypi pico</a> nya.</li>
</ol>[Micropython 4] Mengontrol External LED Menggunakan Push Button2023-08-31T13:32:00+07:002023-08-31T13:32:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-08-31:/micropython-4-mengontrol-external-led-menggunakan-push-button.html<p>Setelah mengetahui bagaimana mengontrol internal led sebagaimana di seri pertama dan ke-2 kemarin, kita akan mencoba untuk mengontrol led external. Kita juga akan buat simulasi lampu kerlap kerlip di akhir nanti. Siapkan alat alatnya ya.</p><p><img alt="Skema" src="https://blog.ihfazh.com/images/led_external_bb.png"></p>
<h1>Bismillah</h1>
<p>Di seri kali ini, kita akan mempelajari bagaimana mengontrol external led menggunakan push button. Kita akan mulai dengan 1 LED saja, dan mempelajari satu persatu komponennya.
Selanjutnya, saya akan ajak untuk membuat lampu kerlap kerlip dari 3 led yang berbeda warna dan berjalan sesuai state nya.</p>
<p>Seperti biasa, asumsi saya kamu telah membeli paket <a href="https://tokopedia.link/mY83NSZNHCb">Get Started With Micropython In Raspberry Pi Pico</a> karena semua yang kita butuhkan di seri seri awal ini ada disana semua. Bila tidak, maka berikut beberapa alat yang kamu perlukan:</p>
<ol>
<li><a href="https://tokopedia.link/QkgWSqRYICb">Breadboard</a></li>
<li><a href="https://tokopedia.link/Rq0eCOYYICb">Raspberry pi pico</a></li>
<li><a href="https://tokopedia.link/jB7zBp2YICb">3 resistor 330 ohm</a></li>
<li><a href="https://tokopedia.link/Yjn7jjfZICb">3 Led berbeda warna (merah, hijau, kuning)</a></li>
<li><a href="https://tokopedia.link/ySO8WBjZICb">Push Button</a></li>
<li>Kabel data micro usb</li>
<li>Beberapa kabel jumper male to male</li>
</ol>
<h3>Kontrol 1 LED</h3>
<h4>Skema</h4>
<p>Untuk mengetahui katub positif dan negatif led, kamu bisa lihat panjang kakinya. Yang lebih panjang maka positif (anoda), dan sebaliknya adalah negatif (katoda). Atau, kamu dapat melihat bagian dalam LED nya, yang lebih kecil adalah positif, dan lebih besar adalah negatif.</p>
<p><img alt="elektronika-dasar.web.id" src="http://elektronika-dasar.web.id/wp-content/uploads/2012/06/Bentuk-Dan-Simbol-LED.jpg"></p>
<p>Gambar dari <a href="http://elektronika-dasar.web.id">elektronika-dasar.web.id</a></p>
<p>Hubungkan kaki positif dengan salah satu kaki resistor, dan kaki resistor satunya hubungkan ke pin 16. Kemudian hubungkan kaki led negatif ke ground.</p>
<p>Adapun push buttonnya, kaki depan kanan hubungkan ke power 3v3, dan kaki belakang kiri ke pin 15.</p>
<p>Berikut gambar skemanya:</p>
<p><img alt="Skema" src="https://blog.ihfazh.com/images/led_external_bb.png"></p>
<h3>Kode</h3>
<p>Ketikkan kode berikut untuk mengontrol led menggunakan push button</p>
<div class="highlight"><pre><span></span><code><span class="c1"># toggle_led.py</span>
<span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="n">led_red</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span>
<span class="n">push_btn</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">handle_toggle</span><span class="p">(</span><span class="n">pin</span><span class="p">):</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">toggle</span><span class="p">()</span>
<span class="n">push_btn</span><span class="o">.</span><span class="n">irq</span><span class="p">(</span><span class="n">handle_toggle</span><span class="p">,</span> <span class="n">trigger</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">IRQ_RISING</span><span class="p">)</span>
</code></pre></div>
<p>Ada yang berbeda dengan <a href="https://blog.ihfazh.com/micropython-2-control-device-dari-luar-menggunakan-push-button">seri sebelumnya</a>? Yap, kita menggunakan method <code>irq</code>. IRQ adalah Interrupt Request. Yakni, sebuah signal yang dikirimkan kepada prosesor untuk mematikan prosesnya sementara.</p>
<p>Jadi, taruhlah pico sedang menjalankan suatu program, misal nyala matikan led secara terus menerus. IRQ ini akan memerintahkan Pico untuk menghentikan sementara program tersebut, dan menjalankan fungsi yang ditentukan sebagai gantinya.</p>
<p>Di kode diatas, sinyalnya adalah perubahan state pada push button. Ketika state push button berubah, maka fungsi <code>handle_toggle</code> akan dipanggil.</p>
<p><code>trigger=Pin.IRQ_RISING</code> sinyalnya akan dikirimkan ketika sedang ada perubahan state dari low ke high, atau dalam kata lain dari 0 menuju 1.</p>
<p>Jalankan program diatas dengan:</p>
<p><code>mpremote run toggle_led.py</code></p>
<p>coba tekan bolak balik buttonnya. </p>
<h3>State LED tidak konsisten</h3>
<p>Yap, benar. State LED tidak konsisten. Terkadang ketika kita tekan button, LED nyala mati dalam satu kali tekan. Terkadang tidak menyala. Apa yang sebenarnya terjadi?</p>
<p>Fenomena ini dinamakan bouncing atau pantulan. Hal ini dikarenakan problem mekanik dari push button itu sendiri, sehingga terkadang terdeteksi buka/tutup dalam sekali tekan. Sehingga, microcontroller membaca beberapa kali perubahan state.</p>
<p>Kita perlu menyelesaikan problem ini dengan mengecek selisih detik terakhir terdeteksi perubahan state dan waktu sekarang. Bila selisihnya paling tidak 300ms, maka kita anggap bahwa ketika push button berubah state, itu adalah perubahan yang kita inginkan.</p>
<p>Perhatikan kode berikut</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">led_red</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span>
<span class="n">push_btn</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="n">latest_click</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span>
<span class="n">delay</span> <span class="o">=</span> <span class="mi">300</span> <span class="c1"># in ms</span>
<span class="k">def</span> <span class="nf">handle_toggle</span><span class="p">(</span><span class="n">pin</span><span class="p">):</span>
<span class="k">global</span> <span class="n">latest_click</span>
<span class="k">if</span> <span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span> <span class="o">-</span> <span class="n">latest_click</span><span class="p">)</span> <span class="o">></span> <span class="n">delay</span> <span class="ow">and</span> <span class="n">pin</span><span class="o">.</span><span class="n">value</span><span class="p">():</span>
<span class="n">latest_click</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">toggle</span><span class="p">()</span>
<span class="n">push_btn</span><span class="o">.</span><span class="n">irq</span><span class="p">(</span><span class="n">handle_toggle</span><span class="p">,</span> <span class="n">trigger</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">IRQ_RISING</span><span class="p">)</span>
</code></pre></div>
<p>Statement <code>global latest_click</code> artinya kita akan mengubah variable diluar fungsi <code>handle_toggle</code>. Bila kita tidak definisikan dengan <code>global</code> statement, maka assignment yang ada di dalam fungsi ini tidak bisa mengubah variable yang diluar.</p>
<p>Perhatikan if statement setelahnya, kita kurangkan ticks sekarang dengan ticks sebelumnya, kemudian kita bandingkan apakah sudah lebih besar dari delay yang kita tentukana atau belum. Bila sudah,
maka kita ubah latest_click dengan tick baru dan lakukan toggle led nya. Bila belum, maka kita tidak melakukan apa apa.</p>
<h3>Satu LED 3 State</h3>
<p>Setelah kita faham bagaimana mengatur LED dengan push button, mari kita ubah program diatas menjadi lebih menarik dan menantang. Kali ini kita akan simpan state LED dan mengubahnya tiap kali kita tekan push button menjadi 3 state dibawah ini:</p>
<ol>
<li>Mati</li>
<li>Nyala terus menerus</li>
<li>Berkedip setiap 1/2 detik</li>
</ol>
<p>Bagaimana alurnya? </p>
<p>Kita buat push button ini sebagai perubah state. Kemudian kita monitor state tersebut dalam while loop. </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">led_red</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span>
<span class="n">push_btn</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="n">latest_click</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span>
<span class="n">delay</span> <span class="o">=</span> <span class="mi">300</span> <span class="c1"># in ms</span>
<span class="n">states</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"mati"</span><span class="p">,</span> <span class="s2">"nyala"</span><span class="p">,</span> <span class="s2">"kedip"</span><span class="p">]</span>
<span class="n">current_state</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">handle_toggle</span><span class="p">(</span><span class="n">pin</span><span class="p">):</span>
<span class="k">global</span> <span class="n">latest_click</span><span class="p">,</span> <span class="n">current_state</span>
<span class="k">if</span> <span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span> <span class="o">-</span> <span class="n">latest_click</span><span class="p">)</span> <span class="o">></span> <span class="n">delay</span> <span class="ow">and</span> <span class="n">pin</span><span class="o">.</span><span class="n">value</span><span class="p">():</span>
<span class="n">latest_click</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">ticks_ms</span><span class="p">()</span>
<span class="n">current_state</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">push_btn</span><span class="o">.</span><span class="n">irq</span><span class="p">(</span><span class="n">handle_toggle</span><span class="p">,</span> <span class="n">trigger</span><span class="o">=</span><span class="n">Pin</span><span class="o">.</span><span class="n">IRQ_RISING</span><span class="p">)</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">state</span> <span class="o">=</span> <span class="n">states</span><span class="p">[</span><span class="n">current_state</span> <span class="o">%</span> <span class="mi">3</span><span class="p">]</span>
<span class="k">if</span> <span class="n">state</span> <span class="o">==</span> <span class="s2">"mati"</span><span class="p">:</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">state</span> <span class="o">==</span> <span class="s2">"nyala"</span><span class="p">:</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">state</span> <span class="o">==</span> <span class="s2">"kedip"</span><span class="p">:</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">led_red</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<p>Sebelum menjalankan script diatas, reset dahulu micropythonnya dengan <code>mpremote reset 0</code>, atau lepas usb dahulu kemudian pasang kembali. Kemudian jalankan program diatas dengan <code>mpremote run led_external.py</code></p>
<p>Kita definisikan states dengan 3 array, mati, nyala dan kedip. Kemudian kita definisikan counter di current_state. Kita juga jadikan <code>current_state</code> sebagai global di handle_toggle sehingga kita dapat mengubah valuenya.</p>
<p>Di while loop, kita dapatkan state sekarang. Kita gunakan trick modulo disini. <code>0 % 3 = 0</code>, <code>1 % 3 = 1</code>, <code>2 % 3 = 3</code>, <code>3 % 3 = 0</code>, dst... Sehingga kita dapatkan index state saat ini tanpa kena IndexError exception.</p>
<p>Setelah kita dapatkan statenya, baru kita jalankan program kita sesuai permintaan diatas.</p>
<h3>3 LED</h3>
<p>Kali ini kita akan menggunakan 3 LED. Yap, bukan saya yang mengerjakan ya. Saya searahkan kepada kamu untuk mengontrol ke-3 LED ini dengan beberapa state berikut:</p>
<p>Gunakan 3 LED berbeda warna. Di sini, saya asumsikan kamu menggunakan hijau, merah dan kuning. Berikut beberapa keadaan lednya:</p>
<ol>
<li>Mati semua</li>
<li>Nyala Semua</li>
<li>Kedip berbarengan (ketiga lampu menyala, kemudian mati, kemudian nyala, dst...)</li>
<li>Menyala satu satu bergantian</li>
<li>Menyala 2 kemudian 1 bergantian</li>
</ol>
<p>Nah, saya serahkan kamu untuk mengerjakan 5 state ini. Kunci jawabannya saya akan sertakan link di akhir artikel.</p>
<p>Hasil akhir kurang lebih seperti ini</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/SenaBzI2K40?si=TiK64HZTBLeKOtgp" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h3>Kenapa butuh resistor ?</h3>
<p>Kalau kamu perhatikan, untuk pemasangan LED butuh resistor, kenapa? Karena LED sendiri membutuhkan voltase sekitar 2 Volt, dan Pin dari raspberry pi pico keluarannya adalah 3.3v. Bila kamu langsung menyambung kaki LED dengan voltase 3.3v maka lampu LED akan meledak.</p>
<p>Sedangkan diantara kegunaan resistor adalah menghambat tegangan. Ketika tegangan dihambat, maka harapannya voltase keluaran sebelum masuk ke LED bisa berkurang. Anggap saja jalan raya yang motor atau mobilnya pada ngebut ngebut. Nah, disuatu tempat ada kecelakaan, atau perbaikan bahu jalan. Mau tidak mau, kecepatan kendaraan yang lewat akan berkurang. Seperti itu kurang lebih analoginya. </p>
<p>Berikut ada beberapa video bagus yang menjelaskan tentang resistor dan LED</p>
<ol>
<li><a href="https://www.youtube.com/watch?v=34_pGkD0Hd0&pp=ygUZZ3VydSBlbGVrdHJvbmlrYSByZXNpc3Rvcg%3D%3D">Resistor, fungsi & prinsip kerja</a></li>
<li><a href="https://www.youtube.com/watch?v=u9oAlR_xnKU&pp=ygUZZ3VydSBlbGVrdHJvbmlrYSByZXNpc3Rvcg%3D%3D">Resistor dan lampu led</a></li>
</ol>
<h3>Penutup</h3>
<p>Nah, bagaimana? Menarik bukan? Di seri ini kamu sudah bisa mengontrol external LED dengan push button. Tidak hanya itu, kamu sudah bisa mengontrol pantulan dari push button, dan juga beberapa lampu LED dengan beberapa state yang berbeda. </p>
<p>Bila belum, kamu bisa <a href="https://gist.github.com/ihfazhillah/c86b67288225efb852c103f2e6a7d30b">check link ini untuk melihat jawaban permasalah 3 LED diatas</a>.</p>
<p>Apa lagi ya yang bisa kita lakukan dengan <a href="https://tokopedia.link/Rq0eCOYYICb">raspberry pi pico</a>? Kita akan lanjutkan pada seri berikutnya insyaAlloh.</p>[Micropython 3] 5 Useful Mpremote Commands2023-08-26T23:43:00+07:002023-08-26T23:43:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-08-26:/micropython-3-5-useful-mpremote-commands.html<p>Sebelum mempelajari micropython lebih lanjut, alangkah baiknya untuk mengetahui beberapa perintah dari mpremote untuk mempermudah development dan juga deployment aplikasi kita ke micropython.</p><h1>Bismillah</h1>
<p>Pada dua seri sebelumnya, kita menuliskan dan menjalankan program kita dari REPLnya micropython. Tidak masalah sih, tapi repot. Iya kan?</p>
<p>Maka dari itu, sebelum kita melanjutkan petualangan dengan micropython, kita akan menelisik lebih lanjut mengenai perintah perintah dari tool <code>mpremote</code>. Tidak semua, tapi beberapa yang dapat mempermudah kita melakukan development maupun deployment nantinya.</p>
<p>Di artikel kali ini, saya akan sampaikan beberapa perintah:</p>
<ol>
<li>Masuk REPL (seperti yang lalu)</li>
<li>Membaca file yang sudah ada di <a href="https://tokopedia.link/Ppgxp55eACb">raspberry pi pico</a></li>
<li>Menjalankan script tanpa harus mencopy script ke <a href="https://tokopedia.link/hIQefkKeACb">raspberry pi pico</a></li>
<li>Menginstall script supaya bisa dijalankan tanpa sambungan komputer</li>
<li>Install library</li>
</ol>
<h3>1. Masuk REPL</h3>
<p>Secara default, memanggil <code>mpremote</code> tanpa tambahan apa apa akan memasukkan kamu ke REPL milik micropython. Atau kalau mau lebih spesifik jalankan</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>repl
</code></pre></div>
<p>Ada beberapa mode dalam micropython REPL:
1. Normal: Yaitu seperti ketika kamu masuk pertama kali
2. Paste: Tekan <code>ctrl+e</code>. Kalau sudah selesai tekan <code>ctrl+d</code></p>
<h3>2. Membaca file</h3>
<p>Terkadang kamu ingin lihat file yang sudah ada di <a href="https://tokopedia.link/5uvJcQLeACb">raspberry pi pico</a> kamu. Kamu bisa jalankan</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>fs<span class="w"> </span>cat<span class="w"> </span>main.py
</code></pre></div>
<p>Artinya, kamu ingin membaca file <code>main.py</code> yang ada di <a href="https://tokopedia.link/5uvJcQLeACb">raspberry pi pico</a>.</p>
<p>atau, kalau mau check directory</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>fs<span class="w"> </span>ls
</code></pre></div>
<h3>3. Jalankan Script tanpa install</h3>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>run<span class="w"> </span>file_kamu.py
</code></pre></div>
<p><code>file_kamu.py</code> adalah file python yang kamu tuliskan di komputer kamu. <code>mpremote</code> akan menjalankan file tersebut di micropython intrepeter tanpa melakukan copy file tersebut kedalam device.</p>
<p>Contoh saja, buat file baru <code>push_button.py</code> dan isi dengan perintah seperti berikut</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">button</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="n">led</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="s2">"LED"</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span> <span class="c1"># atau ganti "LED" dengan 25 kalau menggunakan pico biasa</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">if</span> <span class="n">button</span><span class="o">.</span><span class="n">value</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">led</span><span class="o">.</span><span class="n">toggle</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<p>kemudian jalankan</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>run<span class="w"> </span>push_button.py
</code></pre></div>
<p>Untuk skema bisa lihat ke <a href="https://blog.ihfazh.com/micropython-2-control-device-dari-luar-menggunakan-push-button">artikel yang lalu berikut ini</a></p>
<h3>4. Install Script Agar bisa dijalankan tanpa komputer</h3>
<p>Microcontroller kurang lengkap kalau harus selalu menancap dengan komputer. Untuk bisa menjalankan program setiap kali microcontroller nyala, maka buat file bernama <code>main.py</code>.
Micropython ketika menyala, akan otomatis menjalankan file tersebut.</p>
<p>Lalu, bagaimana menginstall nya? Mudah</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>cp<span class="w"> </span>push_button.py<span class="w"> </span>:main.py<span class="w"> </span>+<span class="w"> </span>reset<span class="w"> </span><span class="m">0</span>
</code></pre></div>
<p>Tenang, mudah saja. <code>cp push_button.py :main.py</code>. Kopi file <code>push_button.py</code> ke device dan ubah menjadi file yang bernama <code>main.py</code>. Untuk perintah copy, awalan <code>:</code> berarti alamat dalam device.</p>
<p><code>+</code> adalah pemisah antar satu perintah dengan perintah yang lainnya. </p>
<p><code>reset 0</code> artinya restart device.</p>
<h3>5. Install Library</h3>
<p>Terkadang kita butuh library tambahan selain yang kita tuliskan. Misal <code>urequests</code> adalah library untuk mudahkan komunikasi API dengan interface seperti package <code>requests</code>. Atau <code>umqtt.simple</code> untuk interaksi dengan protokol <code>mqtt</code>. Bagaimana installnya?</p>
<div class="highlight"><pre><span></span><code>mpremote<span class="w"> </span>mip<span class="w"> </span>urequests
</code></pre></div>
<h2>Penutup</h2>
<p>Nah, itu dia 5 command yang berguna untuk mempermudah kamu melakukan development dan deployment aplikasi pada micropython. Untuk perintah perintah lainnya, kamu bisa konsultasi lebih lanjut ke <a href="https://docs.micropython.org/en/latest/reference/mpremote.html">dokumentasi intinya</a>. </p>
<p>Tentunya kurang lengkap bila hanya membaca, jangan lupa praktek. Kamu bisa membeli <a href="https://tokopedia.link/5uvJcQLeACb">raspberry pi pico dengan paket yang cukup untuk explore seri seri saya ini di sini</a>. <a href="https://tokopedia.link/Ppgxp55eACb">Toko tersebut</a> menjual raspberry pi pico original dan bukan imitasi. Happy Hacking !!</p>[Micropython 2] Kontrol Device Dari Luar Menggunakan Push Button2023-08-17T07:30:00+07:002023-08-17T07:30:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-08-17:/micropython-2-control-device-dari-luar-menggunakan-push-button.html<p>Kali ini kita akan belajar bagaimana menggunakan push button untuk mengontrol internal led dari raspberry pi pico. Kamu akan memhami perbedaan antara Pin.IN dan Pin.OUT disini.</p><p><img alt="Contoh Sambungan" src="https://blog.ihfazh.com/images/push_button_breadboard.png"></p>
<h1>Bismillah</h1>
<p>Pada <a href="https://blog.ihfazh.com/micropython-1-memulai-micropython-menggunakan-raspberrypi-pico">seri yang telah lalu</a>, kita dapat mengontrol internal led menggunakan program. Untuk mendefinisikan bahwa <strong>kita yang akan mengontrol</strong> maka kita menggunakan <code>Pin.OUT</code>. Sehingga, kita dapat mengubah value menjadi 1 dan led akan menyala, ketika kita ubah menjadi 0, led akan mati.</p>
<p>Lalu, bagaimana caranya kita menerima perintah dari dunia luar? Sebagai contoh dengan menggunakan push button? Ketika kita tekan push button, maka led akan menyala. Ketika kita lepas push buttonnya led akan mati?</p>
<p>Micropython punya konstanta <code>Pin.IN</code>. Dengan memasukkannya sebagai argumen kedua sebagain ganti dari <code>Pin.OUT</code>, kita dapat mendapatkan value dari push button tersebut, apakah value nya adalah 1 atau 0.</p>
<h2>Parts</h2>
<p>Saya asumsikan bahwa kamu punya raspberry pi pico dan membeli paket <a href="https://tokopedia.link/SjEhbNpckCb">getting started with raspberry pi pico</a>. Sehingga kamu sudah punya pico, breadboard, beberapa kabel jumper dan juga push button.</p>
<p>Kalau belum, ini yang kamu butuhkan</p>
<table>
<thead>
<tr>
<th style="text-align: left;">Part</th>
<th>toko</th>
<th>rentang harga</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">Raspberry pi pico w</td>
<td><a href="https://tokopedia.link/nelKTdtbkCb">Tokopedia 1</a>, <a href="https://tokopedia.link/pqUQk4vbkCb">Tokopedia 2</a>, <a href="https://tokopedia.link/dTYcQZybkCb">Tokopedia 3</a></td>
<td>Rp 180.000,-</td>
</tr>
<tr>
<td style="text-align: left;">Breadbord</td>
<td><a href="https://tokopedia.link/eIAbJEFbkCb">Tokopedia 1</a>, <a href="https://tokopedia.link/dpyJGBJbkCb">Tokopedia 2</a></td>
<td>Rp 10.000,-</td>
</tr>
<tr>
<td style="text-align: left;">Push button</td>
<td><a href="https://tokopedia.link/WvKOYMQbkCb">Tokopedia 1</a>, <a href="https://tokopedia.link/IxtJRpTbkCb">Tokopedia 2</a>, <a href="https://tokopedia.link/HM2G8sXbkCb">Tokopedia 3</a></td>
<td>Rp 1.000,-</td>
</tr>
<tr>
<td style="text-align: left;">kabel jumper male to male</td>
<td><a href="https://tokopedia.link/BcRNMy4bkCb">Tokopedia 1</a>, <a href="https://tokopedia.link/N2427F9bkCb">Tokopedia 2</a></td>
<td>Rp 12.000,-</td>
</tr>
</tbody>
</table>
<h2>Skema</h2>
<p>Perhatikan, push button memiliki 4 kaki. Bagian yang saya beri tanda saling terkoneksi. Jadi, kita butuh sambungkan salah satu, dari yang depan ke pin <code>3v3</code> (Power). Dan salah satu dari yang belakang ke Pin 15.</p>
<p><img alt="Push Button" src="https://blog.ihfazh.com/images/push_button.jpeg"></p>
<p>Pin yang perlu disambung</p>
<p><img alt="Pin yang perlu dihubungkan" src="https://blog.ihfazh.com/images/micropython_2_pinout.png"></p>
<p>Contoh sambungan
<img alt="Contoh Sambungan" src="https://blog.ihfazh.com/images/push_button_breadboard.png"></p>
<h2>Mendapatkan State Tekan</h2>
<p>Asumsi saya, kamu sudah menginstall <code>mpremote</code> sebagaimana yang telah dijelaskan pada artikel sebelumnya. Ketik <code>mpremote</code> di terminal dan enter.</p>
<p>Selanjutnya, ketik kode di bawah ini:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">button</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">button</span><span class="o">.</span><span class="n">value</span><span class="p">())</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<p>Kode diatas sangatlah simple. Yang kita lakukan adalah membaca pin 15 sebagai masukan.</p>
<p>Kemudian kita melakukan infinite loop untuk melihat value dari button.</p>
<p>Terakhir, kita melakukan sleep selama 0.5 detik.</p>
<p>Kamu akan melihat value adalah <code>0</code> ketika kondisi button tidak kamu tekan. dan <code>1</code> ketika button kamu tekan.</p>
<h3>Kontrol Led dengan Button</h3>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">button</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">PULL_DOWN</span><span class="p">)</span>
<span class="n">led</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="s2">"LED"</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span> <span class="c1"># atau ganti "LED" dengan 25 kalau menggunakan pico biasa</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">if</span> <span class="n">button</span><span class="o">.</span><span class="n">value</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">led</span><span class="o">.</span><span class="n">toggle</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
</code></pre></div>
<p>Semua hampir sama seperti sebelumnya, hanya saja kali ini kita menyalakan atau mematikan led menggunakan push button.
Tekanan pertama berarti menyalakan. Kemudian tekanan selanjutnya berarti mematikan. Dan begitu seterusnya</p>
<h2>Penutup</h2>
<p>class <code>Pin</code> bisa kita gunakan untuk mengatur dan bisa juga kita gunakan untuk menerima perintah. Argumen pertama adalah ID dari pin, dan yang kedua adalah state dia mau jadi apa, input atau output.</p>
<p>Tugas untuk kamu:</p>
<ol>
<li>Buat ketika button kamu tekan, led menyala. Ketika button kamu lepas, led mati.</li>
</ol>
<p>Selamat mencoba.</p>[Micropython 1] Memulai Micropython Menggunakan Raspberry Pi Pico2023-08-10T21:45:00+07:002023-08-10T21:45:00+07:00Ihfazhillahtag:blog.ihfazh.com,2023-08-10:/micropython-1-memulai-micropython-menggunakan-raspberrypi-pico.html<p>Microcontroller membuka ruang untuk programmer untuk bisa memprogram almost anything. Raspberry pi pico adalah salah satunya. Kamu bisa memprogramnya menggunakan python. Yuk check bagaimana cara memulainya.</p><p><img alt="Raspberry Pi Pico" src="https://blog.ihfazh.com/images/raspberry_pi_pico_tangan.jpeg"></p>
<h1>Bismillah</h1>
<p>Microcontroller adalah semisal komputer kecil yang didesain khusus untuk keperluan tertentu. Semisal untuk mengkontrol led, dinamo, membaca sensor dan sebagainya.</p>
<p>Microcontroller ini membuka ruang untuk para programmer untuk bisa mengatur alat alat elektronik dan mengotomatisasinya. </p>
<p>Raspberry pi pico adalah salah satunya. Dia bukan "mini komputer" yang lengkap. Memiliki bentuk kecil, memori kecil, prosesor kecil. Beruntungnya, barang ini sudah masuk indonesia. Mau kloningan atau asli, kamu bisa dapatkan.</p>
<p>Untuk memprogram raspberry pi pico, kamu bisa menggunakan bahasa python. Yaitu dengan menggunakan Micropython. Perlu diingat, karena dia bukan komputer lengkap seperti raspberry pi type b, atau yang lainnya, maka tidak semua fitur python tersedia.</p>
<h3>Installasi</h3>
<p>Raspberry pi pico punya 3 varian, firmware tiap firmware berbeda:</p>
<ol>
<li>Biasa (tanpa wifi dan bluetooth) : https://micropython.org/download/rp2-pico/rp2-pico-latest.uf2</li>
<li>Raspberry pi pico W (dengan wifi) : https://micropython.org/download/rp2-pico-w/rp2-pico-w-latest.uf2</li>
<li>Raspberry pi pico W (dengan wifi dan bluetooth) : https://datasheets.raspberrypi.com/soft/micropython-firmware-pico-w-130623.uf2?_gl=1<em>13lvwpj</em>_ga<em>MTE4NzE0NzU0Ni4xNjg4Mjk5MDUz</em>_ga_22FD70LWDS*MTY5MTYyMTU3My43LjAuMTY5MTYyMTU3My4wLjAuMA..</li>
</ol>
<p>Unduh salah satu sesuai barang yang kamu miliki. Konsultasikan sama <a href="https://tokopedia.link/6X8FclIu8Bb">penjual</a> dimana kamu beli barang tersebut. Kemarin saya beli di <a href="https://tokopedia.link/6X8FclIu8Bb">Khurs IOT</a> dan membeli kedua jenis yang pertama. Link lapak ada dibawah beserta harganya.</p>
<p>Kemudian, hubungkan raspberry pi pico kamu ke komputer. </p>
<p>Secara default, mode pico kamu akan menjadi Mass Storage dengan nama RPI-RP2. </p>
<p>Drag dan Drop uf2 file yang kamu unduh tadi kedalam root dari folder RPI-RP2 tadi.</p>
<p>Setelah selesai proses copy, pico kamu akan reboot, dan akan berubah mode untuk menjalankan micropython yang bisa kamu akses dengan mode serial.</p>
<h3>Hello world</h3>
<p>Install mpremote. </p>
<p><code>pip install mpremote</code></p>
<p>Library ini kita gunakan sebagai alat untuk akses REPL-nya micropython, lihat atau ubah file yang ada di device yang menjalankan pico, atau bisa kita pakai untuk mengecek memory daripada pico kamu.</p>
<p>Setelah selesai, jalankan perintah berikut</p>
<p><code>mpremote</code></p>
<p>Bila <code>mpremote</code> kamu jalankan tanpa argument sama sekali, dia akan menjalankan REPL dari raspberry pi pico pertama yang ditemukan oleh aplikasi ini.</p>
<p>Ketikkan</p>
<div class="highlight"><pre><span></span><code><span class="nb">print</span><span class="p">(</span><span class="s2">"hello world dari micropython"</span><span class="p">)</span>
</code></pre></div>
<p>Selamat, ini adalah langkah awal kamu bisa memprogram barang kecil tapi powerfull ini.</p>
<h3>Menyala matikan led</h3>
<p>Raspberry Pi Pico ini memiliki LED bawaan yang bisa kita program nyala matinya. Tidak seperti seri lainnya, yang mana led digunakan untuk indikator nyala atau tidak, ada proses atau tidak. Di Pico, Led ini mati, dan mereka membiarkan kita untuk memprogramnya.</p>
<p>Tulis ini di REPL</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span>
<span class="n">onboard_led</span> <span class="o">=</span> <span class="n">Pin</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="n">Pin</span><span class="o">.</span><span class="n">OUT</span><span class="p">)</span>
<span class="n">onboard_led</span><span class="o">.</span><span class="n">value</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>
<p>Module <code>machine</code> memungkinkan kamu untuk mengatur hardware yang terintegrasi sama chip pico. Class <code>Pin</code> sendiri adalah class untuk mengontrol pin pin yang terkoneksi dengan dunia luar.</p>
<p>Adapun angka <code>25</code> adalah nomor pin dimana bawaan led pico terkoneksi.</p>
<p>Perlu diperhatikan, Pico seri W menggunakan <code>LED</code> daripada <code>25</code> sebagai argument pertama.</p>
<p>Argument kedua <code>Pin.OUT</code> adalah tanda bahwa kamu yang mengatur hardware tersebut. Misal dalam hal ini menyala matikan LED.</p>
<p>Baris berikutnya, <code>onboard_led.value(1)</code>, kamu menginstruksikan pin 25 untuk mendapatkan arus listrik, sehingga led menyala. </p>
<p>Lalu, bagaimana kamu bisa mematikannya? Mudah, ganti angka value menjadi <code>0</code></p>
<div class="highlight"><pre><span></span><code><span class="n">onboard_led</span><span class="o">.</span><span class="n">toggle</span><span class="p">()</span>
</code></pre></div>
<p>Selain kamu dapat mengontrol secara manual, menyala matikan led dengan memberikan value <code>0</code> atau <code>1</code>. Micropython juga memberikan shortcut untuk melakukan <code>toggle</code>.</p>
<h3>Penutup</h3>
<p>Nah, itu dia perkenalan dengan micropython dan juga raspberry pi pico. Kamu bisa membeli barang tersebut di marketplace.</p>
<table>
<thead>
<tr>
<th style="text-align: left;">Type</th>
<th style="text-align: left;">Link Toko</th>
<th style="text-align: right;">Harga</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;">Biasa</td>
<td style="text-align: left;"><a href="https://tokopedia.link/DKzqu8Os8Bb">Tokopedia</a></td>
<td style="text-align: right;">Rp 139.000</td>
</tr>
<tr>
<td style="text-align: left;">Wifi</td>
<td style="text-align: left;"><a href="https://tokopedia.link/AddaP58r8Bb">Tokopedia</a></td>
<td style="text-align: right;">Rp 170.000</td>
</tr>
<tr>
<td style="text-align: left;">Paket Biasa dan paket Getting Started with micropython</td>
<td style="text-align: left;"><a href="https://tokopedia.link/C5tY9OGs8Bb">Tokopedia</a></td>
<td style="text-align: right;">Rp 265.000</td>
</tr>
</tbody>
</table>
<p>Nah, untuk belajar, paling cocok kita beli yang langsung paket seperti dalam item yang ke 3, atau <a href="https://tokopedia.link/C5tY9OGs8Bb">disini</a>. Piconya sudah siap pasang di breadboard, dan sudah include beberapa sensor, led, saklar yang siap kamu pakai untuk belajar.</p>
<p>Diseri berikutnya, insyaAlloh kita akan belajar bagaimana mendapatkan data dari dunia luar.</p>
<p>Untuk mematikan pico kamu, tinggal cabut saja dari USB port dan matikan pico kamu.</p>How To Get Random Item From Database Using Django2022-12-29T11:37:00+07:002022-12-29T11:37:00+07:00Ihfazhillahtag:blog.ihfazh.com,2022-12-29:/how-to-get-random-item-from-database-using-django.html<p>Are you a Django developer looking to get a random item from a database? We've got the answer for you — learn how here!</p><h1>Bismillah</h1>
<p>Are you a Django developer looking to get a random item from a database? We've got the answer for you — learn how here!</p>
<h3>1. Order by random, then limit 1</h3>
<p>In django, we can sort the queryset by random using <code>order_by('?')</code> then get the first item. Here is the example</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">hello.models</span> <span class="kn">import</span> <span class="n">Article</span>
<span class="n">random_article</span> <span class="o">=</span> <span class="n">Article</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s2">"?"</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
</code></pre></div>
<p>However, this will scan through all rows in the database first. Then pick one result randomly.</p>
<p>Ofcourse, if the database has millions rows, this will slow down the database server and maybe kill your server.
We should have another way to retrieve the random data.</p>
<h3>2. Get the max id, get id randomly.</h3>
<p>This only applicable if you have auto increment id. And in Django, this is the default one.</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">random</span>
<span class="n">max_id</span> <span class="o">=</span> <span class="n">Article</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s2">"id"</span><span class="p">)</span><span class="o">.</span><span class="n">last</span><span class="p">()</span>
<span class="n">random_id</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">max_id</span><span class="p">)</span>
<span class="n">random_article</span> <span class="o">=</span> <span class="n">Article</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="n">random_id</span><span class="p">)</span>
</code></pre></div>
<p>although this method requires 2 hit into database, but this will more efficient for the larger database.</p>
<h3>How if the record not found?</h3>
<p>Good catch!</p>
<p>Sometimes we deleted a row or multiple rows. Then when random_id match with the deleted rows, the django application will roar into us
"Hey, the record doesn't exist"</p>
<p>How we can avoid that? </p>
<p>Well, you can do a <code>try</code> <code>except</code> until the record found.</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">random</span>
<span class="n">article</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">max_id</span> <span class="o">=</span> <span class="n">Article</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s2">"id"</span><span class="p">)</span><span class="o">.</span><span class="n">last</span><span class="p">()</span>
<span class="k">while</span> <span class="n">article</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">random_id</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">max_id</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">article</span> <span class="o">=</span> <span class="n">Article</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="n">random_id</span><span class="p">)</span>
<span class="k">except</span> <span class="n">Article</span><span class="o">.</span><span class="n">DoesNotExists</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"article with id: </span><span class="si">{</span><span class="n">random_id</span><span class="si">}</span><span class="s2"> not found. Trying again..."</span><span class="p">)</span>
</code></pre></div>
<h3>Conclusion</h3>
<p>That is:</p>
<ul>
<li>go with <code>order_by('?')</code> if you know the records not so big, or you have a big memory for your database.</li>
<li>go with the second option, if you have many many of rows. Although it requires 2 or more hit into database, but the memory consumption is not so big.</li>
</ul>How To Zip Folder in Python2022-12-11T22:35:00+07:002022-12-11T22:35:00+07:00Ihfazhillahtag:blog.ihfazh.com,2022-12-11:/zipping-in-python.html<p>Zip folder in django on the fly.</p><h1>Bismillah</h1>
<p>How if you want to provide your user a list of files in your backend server, and you want to provide them a zip file generated on the fly?</p>
<p>This article will cover that using python, and django framework. Let's dive in.</p>
<hr>
<p>You can use <code>ZipFile</code> library to handle such condition. The constructor need a required parameter called <code>file</code>. The <code>file</code> parameter can be:
- a string. If a string provided, then ZipFile will use it as a path.
- a File object
- a file like object
- a path file like object</p>
<p>And the second parameter was an opening mode flag. Think like <code>open</code> library. <code>r</code> for read, and <code>w</code> as write, etc...</p>
<p>and also, you can use instance of <code>ZipFile</code> as context manager. That means if you go outside the <code>with</code> block, the zip file will be closed automatically.</p>
<hr>
<p>Let's try to create a zip file from a folder. Supposed you have tree like this</p>
<div class="highlight"><pre><span></span><code>folder
-<span class="w"> </span>audio1
-<span class="w"> </span>audio2
-<span class="w"> </span>audio3
</code></pre></div>
<p>After creating a <code>ZipFile</code> instance, you can use method <code>write</code> that accept <code>filename</code> parameter. </p>
<p>In the following example, you can see I use the <code>arcname</code> parameter. This is optional. If not specified, the filename inside the zip file will match <code>filename</code> and stored in the one level.</p>
<p>But, if you want to persist the directory structure, you should specify this.</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">zipfile</span> <span class="kn">import</span> <span class="n">ZipFile</span>
<span class="c1"># we assume that the active directory was </span>
<span class="c1"># same level with the `folder`</span>
<span class="k">with</span> <span class="n">ZipFile</span><span class="p">(</span><span class="s1">'folder.zip'</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">compressor</span><span class="p">:</span>
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="s2">"folder"</span><span class="p">):</span>
<span class="n">compressor</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">arcname</span><span class="o">=</span><span class="n">f</span><span class="p">)</span>
</code></pre></div>
<hr>
<p>Okay, that's enough. Let's use it in django. You may thinking to create a temporary file using <code>tempfile</code> library.</p>
<p>But, think again!</p>
<p>Django's <code>Response</code> was a File like object. You can use it as first parameter of <code>ZipFile</code> instead of create a temp file, then deleting it.</p>
<div class="highlight"><pre><span></span><code> <span class="n">files</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"abc.txt"</span><span class="p">,</span> <span class="s2">"def.txt"</span><span class="p">,</span> <span class="s2">"ghi.txt"</span><span class="p">]</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">HttpResponse</span><span class="p">(</span>
<span class="n">content_type</span><span class="o">=</span><span class="s2">"application/zip"</span><span class="p">,</span>
<span class="n">headers</span><span class="o">=</span><span class="p">{</span>
<span class="s2">"Content-Disposition"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"attachment; filename=helloworld.zip"</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="k">with</span> <span class="n">zipfile</span><span class="o">.</span><span class="n">ZipFile</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">compressor</span><span class="p">:</span>
<span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="n">compressor</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">default_storage</span><span class="o">.</span><span class="n">path</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">file</span><span class="si">}</span><span class="s2">"</span><span class="p">),</span> <span class="n">arcname</span><span class="o">=</span><span class="n">file</span><span class="p">)</span>
<span class="k">return</span> <span class="n">response</span>
</code></pre></div>
<p>That's it. </p>
<hr>
<p>Refs:</p>
<ul>
<li>https://docs.python.org/3/library/zipfile.html</li>
<li>https://docs.djangoproject.com/en/4.1/howto/outputting-csv</li>
</ul>RWID Privacy Policy2021-05-16T07:34:00+07:002021-05-16T07:34:00+07:00Ihfazhillahtag:blog.ihfazh.com,2021-05-16:/rwid-privacy-policy.html<p><strong>Privacy Policy</strong></p>
<p>Muhammad Ihfazhillah built the RemoteWorker Indonesia app as an Open Source app. This SERVICE is provided by Muhammad Ihfazhillah at no cost and is intended for use as is.</p>
<p>This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information …</p><p><strong>Privacy Policy</strong></p>
<p>Muhammad Ihfazhillah built the RemoteWorker Indonesia app as an Open Source app. This SERVICE is provided by Muhammad Ihfazhillah at no cost and is intended for use as is.</p>
<p>This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.</p>
<p>If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.</p>
<p>The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at RemoteWorker Indonesia unless otherwise defined in this Privacy Policy.</p>
<p><strong>Information Collection and Use</strong></p>
<p>For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information. The information that I request will be retained on your device and is not collected by me in any way.</p>
<p><strong>Log Data</strong></p>
<p>I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.</p>
<p><strong>Cookies</strong></p>
<p>Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.</p>
<p>This Service does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.</p>
<p><strong>Service Providers</strong></p>
<p>I may employ third-party companies and individuals due to the following reasons:</p>
<ul>
<li>To facilitate our Service;</li>
<li>To provide the Service on our behalf;</li>
<li>To perform Service-related services; or</li>
<li>To assist us in analyzing how our Service is used.</li>
</ul>
<p>I want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.</p>
<p><strong>Security</strong></p>
<p>I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.</p>
<p><strong>Links to Other Sites</strong></p>
<p>This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.</p>
<p><strong>Children’s Privacy</strong></p>
<p>These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information from children under 13 years of age. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do necessary actions.</p>
<p><strong>Changes to This Privacy Policy</strong></p>
<p>I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page.</p>
<p>This policy is effective as of 2021-05-16</p>
<p><strong>Contact Us</strong></p>
<p>If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at me@ihfazh.com.</p>
<p>This privacy policy page was created at <a href="https://privacypolicytemplate.net">privacypolicytemplate.net</a> and modified/generated by <a href="https://app-privacy-policy-generator.nisrulz.com/">App Privacy Policy Generator</a></p>How To Hide Some Field in Django Queryset2019-07-19T10:45:00+07:002019-07-19T10:45:00+07:00Ihfazhillahtag:blog.ihfazh.com,2019-07-19:/how-to-hide-some-field-in-django-queryset.html<p>The original problem is, how to not select particular field when do a query in Django model? There're some approach to handle this problem. I'll show you three approaches to handle this. Keep Reading, and give your thoughts.</p><h1>Bismillah</h1>
<h2>Introduction</h2>
<p>When work with user permission, sometimes we need to hide some field for particular user not other. In Django, you can use approaches that I will mention here in this article.</p>
<p>The objectives of this article are:</p>
<ol>
<li>Problem Definition</li>
<li>Approaches to handle this problem.</li>
</ol>
<p>Lets dive into the problem definition or the user story.</p>
<h2>1. Problem Definition</h2>
<h3>User Story</h3>
<p>A teacher can create a quiz, write description, and questions for that quiz. But, Don't display the questions into student that not registered into that quiz.
Only teacher who create the quiz, and registered user can see the questions of the quiz. Plus: the quiz will expired after 10 days.</p>
<h3>Break Down</h3>
<p>So, there are some points:</p>
<ol>
<li>Teacher User create quiz</li>
<li>Quiz detail view, only these users can see the questions:<ul>
<li>Teacher who created the quiz</li>
<li>Students who registered to that quiz</li>
</ul>
</li>
<li>Quiz expiration</li>
</ol>
<p>In this article, we will only focus on the second point. We will make assumptions for the first point and third point in the section below.</p>
<h3>Assumptions</h3>
<h4>The model</h4>
<p>We have 2 user model, Teacher and Student. Then another two model for Quiz and Question. For simplicity, we will define these simple models in our models.py</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">Teacher</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">Student</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">Quiz</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">()</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>
<span class="n">created_by</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Teacher</span><span class="p">)</span>
<span class="n">students</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToMany</span><span class="p">(</span><span class="n">Student</span><span class="p">)</span>
<span class="n">_is_expired</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">verbose_name</span><span class="o">=</span><span class="s1">'is_expired'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">created_at</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">auto_now_add</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">is_expired</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_expired</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="c1"># some logic to check expiration, and update the _is_expired to True if expired</span>
<span class="k">return</span> <span class="n">is_expired</span> <span class="c1"># assumed that is_expired defined</span>
<span class="k">class</span> <span class="nc">Question</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>
<span class="n">quiz</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Quiz</span><span class="p">)</span>
</code></pre></div>
<h4>What Is is_expired property</h4>
<p>It's to prevent django do make calculation when the quiz already expired.</p>
<h3>2. Approaches</h3>
<p>There are some approaches, to handle hiding values to achieve our problem here.
In this article, we will talk about three approaches. I'll try to cover how-to, some short explanation if required and the plus-minus for each approach.</p>
<p>Lets dive in...</p>
<h4>1. Let developer decide the permission in the template</h4>
<p>Okay, Its a simple approach. Make a query for a quiz, and pass it into the template's context. Then, let developer to decide what fields of quiz will displayed into a user, and not displayed in the template.</p>
<p>Let's look at the implementation:</p>
<div class="highlight"><pre><span></span><code><span class="x"># views.py</span>
<span class="x">def detail_quiz(request, pk):</span>
<span class="x"> quiz = get_object_or_404(Quiz, pk=pk)</span>
<span class="x"> return render_template(request, templatename, {'quiz': quix})</span>
<span class="x"># in template</span>
<span class="c">{# to show questions #}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">request.user</span> <span class="o">==</span> <span class="nv">quiz.created_by</span> <span class="k">or</span> <span class="nv">request.user</span> <span class="k">in</span> <span class="nv">quiz.students.all</span><span class="o">()</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">question</span> <span class="k">in</span> <span class="nv">quiz.questions.all</span><span class="o">()</span> <span class="cp">%}</span>
<span class="x"> {# show the questions %}</span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="x">Only Registered user can see the questions</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</code></pre></div>
<p>This can be done in Django because of the django's reverse relationship.</p>
<p><strong>The Pros</strong>:</p>
<ul>
<li>Simple view, yes we only do query for quiz</li>
</ul>
<p><strong>The Cons</strong>:</p>
<ul>
<li>Decision logic at your template. This is not intended to be placed in the template. The template is only place for representational purpose.</li>
<li>When developer forgot to filter user, all user can see all questions.</li>
</ul>
<h4>2. Disable reverse relations</h4>
<p>Okay, back to the model, at Question model we change to:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Question</span>(<span class="n">models</span>.<span class="n">Model</span>):
<span class="n">text</span> = <span class="n">models</span>.<span class="n">TextField</span>()
<span class="n">quiz</span> = <span class="n">models</span>.<span class="n">ForeignKey</span>(<span class="n">Quiz</span>, <span class="n">related_name</span>=<span class="s">'+'</span>)
</code></pre></div>
<p>when we use <code>related_name='+'</code> in the <code>ForeignKey</code> we disable reverse relation. With that in our mind, we can't do query like this <code>quiz.questions.all()</code>.</p>
<p>So, how we can decide user that has permission to see questions and not?</p>
<div class="highlight"><pre><span></span><code>def detail_quiz(request, pk):
quiz = get_object_or_404(Quiz, pk=pk)
context = {
'quiz': quiz
}
allowed_see_questions = any([
request.user == quiz.created_by,
request.user in quiz.students.all()
])
if allowed_see_questions:
context['questions'] = Question.objects.filter(quiz=quiz)
return render_template(request, templatename, context)
</code></pre></div>
<p>You can see, we pass <code>questions</code> as context when user is allowed to see questions. If not, we not pass anything about questions. And in template, we only make test: <code>if questions</code>.</p>
<p><strong>The Pros</strong></p>
<ul>
<li>this is the place for things like that. As view in django is a controller.</li>
<li>no permission checking in the template</li>
</ul>
<p><strong>The Cons</strong>
- yes, more code in view / controller</p>
<h4>3. use values in queryset</h4>
<p>Another way is to use <code>values</code> in the queryset. It's called like <code>Quiz.objects.values('description').all()</code>. Its will return queryset with dictionary object with key described in the <code>values</code> params for each item. It's just like <code>SELECT a, b, c FROM x</code> in the SQL query.</p>
<p>This is best way to do for the most field permissions. But, in our case, we want to access <code>is_expired</code> property in the quiz object. So, we can't do <code>values</code> at this problem.</p>
<h2>At The End</h2>
<p>Yes, I think there are more and more approaches to handle situation like this. If you have any, you can contribute to me in the comment below. And we can share our decission to help other developers if they have problem like this.</p>
<p>So, That is 3 approaces to problem like I described before. And thanks for your time and reading..</p>How To Implement Google Recaptcha v3 on Your Django App2019-05-22T13:06:00+07:002019-05-22T13:06:00+07:00Ihfazhillahtag:blog.ihfazh.com,2019-05-22:/how-to-implement-google-recaptcha-v3-on-your-django-app.html<p>Steps to implement google recaptcha v3 on django app, frontend and backend with an example examples.</p><p>In this tutorial, I will show you how to implement google recaptcha v3 into your django app.</p>
<p>I also already create a simple django app, and what we will do here only to integrate the google recaptcha v3 in some views.</p>
<p>Let's get started.</p>
<h2>Clone App</h2>
<p>Clone https://github.com/ihfazhillah/django-recaptchav3-example, then optionally create a virtualenv. Install the dependency.</p>
<p>FYI, the repo has 2 branches. <code>master</code> and <code>final</code>. Just start with <code>master</code> branch, and you can get the final result in the <code>final</code> branch.</p>
<h2>Step 1: Register Google Recaptcha and Choose v3</h2>
<p>Go to https://g.co/recaptcha/v3, then create a new site. </p>
<p><img alt="registration" src="https://blog.ihfazh.com/images/recaptchav3/google_recaptcha_registration.png"></p>
<p>Insert your Label, choose reCaptcha v3 in the recaptcha type.</p>
<p>Add <code>localhost</code> and <code>127.0.0.1</code> into <code>domains</code> field for local testing.</p>
<p>Accept the TOS. And then click submit.</p>
<p><img alt="secret_key and site_key" src="https://blog.ihfazh.com/images/recaptchav3/registered_recaptcha.png"></p>
<p>You will see <code>secret key</code> and <code>site key</code>. The site key is what you need to implement google recaptcha v3 in the frontend. And secret key, keep it secret. This will be used for g-recaptcha's frontend response verification on your backend.</p>
<h2>Step 2: Put Keys Into settings.py</h2>
<p>Grab <code>secret_key</code> and <code>site_key</code> into <code>settings.py</code> like this:</p>
<div class="highlight"><pre><span></span><code>RECAPTCHA_SITE_KEY = "your site key"
RECAPTCHA_SECRET_KEY = "your secret key"
</code></pre></div>
<p>and add site key into your index view</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> simple render index.html</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'index.html'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'site_key'</span><span class="p">:</span> <span class="n">settings</span><span class="o">.</span><span class="n">RECAPTCHA_SITE_KEY</span><span class="p">})</span>
</code></pre></div>
<h2>Step 3: Implement g-recaptcha on your frontend</h2>
<p>open <code>templates/index.html</code> and add this javascript script:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span>//<span class="w"> </span>1
<span class="w"> </span><span class="nt"><script</span><span class="w"> </span><span class="na">src=</span><span class="s">"https://code.jquery.com/jquery-3.4.1.min.js"</span><span class="w"> </span><span class="na">integrity=</span><span class="s">"sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="</span>
<span class="w"> </span><span class="na">crossorigin=</span><span class="s">"anonymous"</span><span class="nt">></script></span>
<span class="w"> </span>//<span class="w"> </span>2
<span class="w"> </span><span class="nt"><script</span><span class="w"> </span><span class="na">src=</span><span class="s">"https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"</span><span class="nt">></script></span>
<span class="w"> </span><span class="nt"><script></span>
<span class="w"> </span>//<span class="w"> </span>3
<span class="w"> </span>grecaptcha.ready(function()<span class="w"> </span>{
<span class="w"> </span>//<span class="w"> </span>4
<span class="w"> </span>$('#contactform').submit(function(e){
<span class="w"> </span>var<span class="w"> </span>form<span class="w"> </span>=<span class="w"> </span>this;
<span class="w"> </span>//<span class="w"> </span>5
<span class="w"> </span>e.preventDefault()
<span class="w"> </span>grecaptcha.execute('reCAPTCHA_site_key',<span class="w"> </span>{action:<span class="w"> </span>'contactform'}).then(function(token)<span class="w"> </span>{
<span class="w"> </span>//<span class="w"> </span>6
<span class="w"> </span>$('#recaptcha').val(token)
<span class="w"> </span>//<span class="w"> </span>7
<span class="w"> </span>form.submit()
<span class="w"> </span>});
<span class="w"> </span>})
<span class="w"> </span>});
<span class="w"> </span><span class="nt"></script></span>
</code></pre></div>
<ol>
<li>Use <code>jquery</code> to work with selector. It will make selection easier.</li>
<li>Render the recaptcha v3 in your page</li>
<li>when recaptcha ready, then</li>
<li>when user click on submit button, execute grecaptcha to get the response token</li>
<li>include the response token into form request and we will verify it on the backend</li>
</ol>
<p>and add this hidden input in the form</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nx">input</span><span class="w"> </span><span class="k">type</span><span class="p">=</span><span class="s">"hidden"</span><span class="w"> </span><span class="nx">name</span><span class="p">=</span><span class="s">"g-recaptcha-response"</span><span class="w"> </span><span class="nx">id</span><span class="p">=</span><span class="err">'</span><span class="nx">recaptcha</span><span class="err">'</span><span class="p">></span>
</code></pre></div>
<p>now recaptcha activated !</p>
<p><img alt="activated" src="https://blog.ihfazh.com/images/recaptchav3/recaptcha_active.png"></p>
<h2>Step 4: Implement g-recaptcha verification on your backend</h2>
<p>open <code>recaptcha_example/views.py</code> and write down this on the <code>contact</code> view function:</p>
<div class="highlight"><pre><span></span><code> secret_key = settings.RECAPTCHA_SECRET_KEY
# captcha verification
data = {
'response': data.get('g-recaptcha-response'),
'secret': secret_key
}
resp = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
result_json = resp.json()
print(result_json)
if not result_json.get('success'):
return render(request, 'contact_sent.html', {'is_robot': True})
# end captcha verification
</code></pre></div>
<ol>
<li>Get recaptcha response token from frontend.</li>
<li>verify it </li>
<li>if <code>success</code> true we can assumse that the user is not a robot, and process whole request</li>
<li>if not, return error.</li>
<li>Don't forget to install <code>requests</code> package</li>
</ol>
<p>If you curious, this is example of response from g-recaptcha verification</p>
<div class="highlight"><pre><span></span><code>{'success': True, 'challenge_ts': '2019-05-22T05:43:19Z', 'host
name': 'localhost', 'score': 0.9, 'action': 'contactform'}
</code></pre></div>
<p>and I'm not a robot. Yay...</p>
<h2>Conclusion</h2>
<p>That's all. We use google recaptcha v3, so there are no interruption to our visitor and we will get a score between 0.0 into 1.0 to indicate the visitor is a robot or human.</p>
<p>Thanks for reading, and hope you can implement it into your next project.</p>How To: Scrape Website Menggunakan JSON Data2019-03-25T22:58:00+07:002019-03-25T22:58:00+07:00Ihfazhillahtag:None,2019-03-25:-scrape-website-menggunakan-json-data.html<p>Library untuk melakukan screen scraping menggunakan json sebagai selector, dan juga bentuk data yang ingin di dapatkan. Kemudian me-result data dengan bentuk json.</p><h1>Bismillah</h1>
<p>Berawal dari sebuah ide, scraping website bermodalkan sebuah template. Template ini adalah spesifikasi bentuk data yang akan di dapatkan.</p>
<p>Output dari program adalah data yang telah kamu spesifikasikan.</p>
<p>Misalkan ada template seperti berikut:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"//p[@class='name']/text()"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"getter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"getall"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>dan akan mengembalikan data dengan bentuk kurang lebih :</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"Ihfazh"</span><span class="p">,</span><span class="w"> </span><span class="s2">"sakinah"</span><span class="p">,</span><span class="w"> </span><span class="s2">"fukaihah"</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<p>Beberapa keuntungan menggunakan konsep seperti ini:</p>
<ol>
<li>DRY (Don't repeat yourself). Untuk task sesederhana ini, kita tidak perlu import requests, beautifulsoup / parsel.Selector. Tinggal buat template, panggil template dan url tujuan. Simple</li>
<li>Data sudah terstruktur, sesuai yang kita spesifikasikan.</li>
<li>Mungkin, kamu ada ide lain untuk buat SaaS :D</li>
</ol>
<p>Kabar baiknya, saya sudah mulai buat library ini, meskipun simple namun sudah cukup membantu. Ide awal sudah berjalan dengan baik.</p>
<h2>Installasi</h2>
<h3>Menggunakan PIP</h3>
<div class="highlight"><pre><span></span><code>pip install pyinstantcrawl
</code></pre></div>
<h3>Clone dari github</h3>
<div class="highlight"><pre><span></span><code>git clone https://github.com/ihfazhillah/py-instant-crawl.git
cd py-instant-crawl
python setup.py install
</code></pre></div>
<h2>Quickstart</h2>
<p>Sebagai contoh, kita akan scrape https://www.producthunt.com/protips dan ambil tips yang ada di halaman tersebut.</p>
<h3>1. Buat template</h3>
<p>Data yang akan kita dapatkan ada di class <code>.protips_[somenumber]</code>. Dan dengan membungkus xpath selector dengan <code>string()</code>, kita akan dapatkan text tanpa tag html.</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"protips"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string(//div[contains(@class, 'protips')])"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"getter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>dan simpan dengan nama <code>protips.json</code>.</p>
<p>Jadi, setiap key kita butuh 3 property:</p>
<ol>
<li><code>expression</code> : xpath atau css expression, sesuai yang kamu spesifikasikan di <code>type</code></li>
<li><code>type</code>: string, <code>xpath</code> atau <code>css</code></li>
<li><code>getter</code>: string, <code>get</code> atau <code>getall</code>. <code>get</code> akan ambil hasil pertama. Bila tidak ada, maka akan mengembalikan <code>None</code>. <code>getall</code> akan mengembalikan list.</li>
</ol>
<h3>2. panggil script dan pipe ke file kalau mau</h3>
<div class="highlight"><pre><span></span><code>pyinstantcrawl https://www.producthunt.com/protips protips.json
# atau simpan ke file
pyinstantcrawl https://www.producthunt.com/protips protips.json > producthunt-protips-result.json
</code></pre></div>
<h2>Dengan children</h2>
<p>Ketika mengambil data dari suatu website, seringnya kita butuh beberapa
attribut dari item. Dan, <code>pyinstantcrawl</code> support itu.
Caranya: tambahkan property <code>children</code> di setiap item.</p>
<p>Sebagai contoh:</p>
<div class="highlight"><pre><span></span><code>Posts
|_ title
|_ url
|_ date
</code></pre></div>
<p>Sehingga, contoh json selector-nya adalah sebagai berikut:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"contents"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"//section[@id='content']/ul/li"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"children"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"datetime"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./time/text()"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"getter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./a/@href"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"getter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">"title"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"expression"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./a/text()"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xpath"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"getter"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>simpan script diatas dengan <code>sample_with_child.json</code>, kemudian panggil dengan
<code>pyinstantcrawl https://blog.ihfazh.com/archives.html sample_with_child.json</code></p>
<p>Di setiap children item, kita juga bisa kasih children lagi, dan di dalamnya
lagi seterusnya.</p>
<hr>
<p>Perhatikan !</p>
<p><code>"expression": "./time/text()"</code>, dot kemudian diteruskan dengan selector.
Maksudnya adalah selector / expression ini adalah relative dari
parentnya. Dengan kata lain ini seperti <code>parent_selector.child_selector</code>.
Kalau kita hilangkan dot, maka selector akan memulai lagi dari awal dokumen.</p>
<h2>Sebagai library</h2>
<p>Kitapun dapat menggunakan <code>pyinstantcrawl</code> sebagai python library. Buka python intrepeter dan tuliskan kode berikut:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pyinstantcrawl</span>
<span class="n">sample_json</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">{</span>
<span class="s2"> "articles": {</span>
<span class="s2"> "expression": "//section[@id='listing']/article",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "children": {</span>
<span class="s2"> "url": {</span>
<span class="s2"> "expression": ".//header//a/@href",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "getter": "get"</span>
<span class="s2"> },</span>
<span class="s2"> "title": {</span>
<span class="s2"> "expression": ".//header//a/text()",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "getter": "get"</span>
<span class="s2"> },</span>
<span class="s2"> "tags": {</span>
<span class="s2"> "expression": ".//header//div[has-class('w3-margin-right')][not(contains(@class, 'w3-opacity'))]/span",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "children": {</span>
<span class="s2"> "url": {</span>
<span class="s2"> "expression": "./a/@href",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "getter": "get"</span>
<span class="s2"> },</span>
<span class="s2"> "title": {</span>
<span class="s2"> "expression": "./a/text()",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "getter": "get"</span>
<span class="s2"> }</span>
<span class="s2"> }</span>
<span class="s2"> }</span>
<span class="s2"> }</span>
<span class="s2"> },</span>
<span class="s2"> "next": {</span>
<span class="s2"> "expression": "//ul[has-class('w3-pagination')]/li/a[not(contains(@class, 'w3-green'))][last()]/@href",</span>
<span class="s2"> "type": "xpath",</span>
<span class="s2"> "getter": "get"</span>
<span class="s2"> }</span>
<span class="s2">}</span>
<span class="s2">"""</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">pyinstantcrawl</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s1">'https://blog.ihfazh.com'</span><span class="p">,</span> <span class="n">sample_json</span><span class="p">)</span>
</code></pre></div>
<h2>Penutup</h2>
<p><code>pyinstantcrawl</code> masih sangat baru, belum ada exception handling sama sekali. But its works as expected.</p>
<p>Untuk scrape simple website, <code>pyinstantcrawl</code> sudah cukup mengurangi "melanggar" DRY.</p>
<p><code>pyinstantcrawl</code> juga cocok sebagai base dari <em>turn any website into json</em>. Atau dengan kata lain, untuk layanan mengubah website menjadi json, yang nantinya dipanggil dari frontend framework semisal reactjs, vue, angular, jquery atau lainnya bisa kamu sebutkan sendiri satu satu.</p>
<h3>Lebih lanjut:</h3>
<ul>
<li>https://parsel.readthedocs.io/en/latest/usage.html#using-selectors</li>
<li>https://www.w3schools.com/xml/xpath_syntax.asp</li>
<li>https://www.w3schools.com/cssref/css_selectors.asp</li>
</ul>(bashtips) Timer di Bash2019-03-09T17:40:00+07:002019-03-09T17:40:00+07:00Ihfazhillahtag:blog.ihfazh.com,2019-03-09:/(bashtips)-timer-di-bash.html<p>membuat timer di bash, pomodoro, atau yang lainnya.</p><h1>Bismillah</h1>
<p>Suatu hari, saya mulai bekerja. Namun karena suatu hal, 1 jam berikutnya saya harus melakukan sesuatu yang lainnya. Hari hari, memang saya banyak bekerja di terminal. Saya butuh semisal <code>timer 60h</code> dan enter, kemudian saya mulai bekerja. Setelah 1 jam, saya mendapat peringatan.</p>
<h2>Installasi</h2>
<p>Di linux, pastikan sudah ada ini:
- bc
- sox
- libsox-fmt-mp3</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>-o<span class="w"> </span>~/bin/timer<span class="w"> </span>https://raw.githubusercontent.com/rlue/timer/master/bin/timer
$<span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>~/bin/timer
</code></pre></div>
<h2>How to Use</h2>
<ul>
<li><code>timer 5</code> => 5 menit kemudian, kamu akan mendapatkan notifikasi</li>
<li><code>timer -r 10 500</code> => 500 menit kemudian, kamu akan mendapatkan notifikasi. 10x</li>
<li><code>timer 10 20 30</code> => berurut, pertama 10 menit, kemudian 20 menit, kemudian 30 menit.</li>
</ul>
<h2>Penutup</h2>
<p>Meskipun saya berada di depan laptop, dan mostly berada di depan terminal, saya dengan mudah dapat membuat semisal alarm untuk membantu saya mengingat waktu. Paling nggak, molor dikit. Ha ha.</p>
<p>Semoga membantu..</p>Django Custom Widget With 3 Examples2018-12-02T23:18:00+07:002018-12-02T23:18:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-12-02:/django-custom-widget-with-3-examples.html<p>Learn How to Create Custom Widget in django, either with version 2.1 or 1.8</p><h3>Intro</h3>
<p>Hi folks, in this article we will create 3 custom widgets for django apps. The widget in the django term is a field html display in the form. For instance, <code>CharField</code> this default widget is <code>TextInput</code> that render <code><input type='text' ..../></code>. <code>FileField</code> the default widget is <code>FileInput</code> that render <code><input type='file' .../></code>.</p>
<p>We will create a toggle widget, 2 select that use <code>select2</code> component, and the last is a file input using <code>dropzone</code>. We will walk step by step from the easy one to the hardest part. And at end tutorial, I hope you can create your own very awesome django widget.</p>
<p>This tutorial is for django 1.8 and 2.1 versions. And you can found the code at https://gitlab.com/ihfazhillah/django-custom-widget-code.git and look at <code>django-lt-1.11</code> branch for > 1.8 version and <code>django-gt-1.11</code> branch for the 2.1 version.</p>
<h3>Initialization</h3>
<p>Lets create two new django projects. First for 1.8 and second for 2.1. Use <code>pipenv</code> to make your live easier :D.</p>
<div class="highlight"><pre><span></span><code><span class="n">pipenv</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">Django</span><span class="o">==</span><span class="mf">2.1</span>
<span class="n">pipenv</span><span class="w"> </span><span class="n">shell</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">virtualenv</span><span class="w"> </span><span class="n">shell</span>
<span class="n">django</span><span class="o">-</span><span class="k">admin</span><span class="w"> </span><span class="n">startproject</span><span class="w"> </span><span class="n">custom_widget</span>
</code></pre></div>
<p>and </p>
<div class="highlight"><pre><span></span><code><span class="n">pipenv</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">Django</span><span class="o">==</span><span class="mf">1.8</span>
<span class="n">pipenv</span><span class="w"> </span><span class="n">shell</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">virtualenv</span><span class="w"> </span><span class="n">shell</span>
<span class="n">django</span><span class="o">-</span><span class="k">admin</span><span class="w"> </span><span class="n">startproject</span><span class="w"> </span><span class="n">custom_widget</span>
</code></pre></div>
<p>Then, go to each of <code>custom_widget</code> folder and run <code>python manage.py runserver</code> and make sure that two servers works.</p>
<p>PS: Don't forget to different the port.</p>
<p>Time to create a new view.</p>
<p>Open <code>custom_widget/custom_widget/views.py</code> and add these lines.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="k">def</span> <span class="nf">home</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span>
<span class="n">request</span><span class="p">,</span>
<span class="s1">'home.html'</span><span class="p">,</span>
<span class="n">context</span>
<span class="p">)</span>
</code></pre></div>
<p>In this view, we will handle all stuff. The form, and the values. You can see, that we use <code>home.html</code> as template. To make it work, we need to specify <code>TEMPLATES['DIRS']</code> setting.
Open the <code>settings.py</code> file and make change a change.</p>
<div class="highlight"><pre><span></span><code>TEMPLATES = [
{
.....................................................................
'DIRS': [
os.path.join(BASE_DIR, 'templates')
],
.........................
</code></pre></div>
<p>save and then create <code>templates</code> folder at <code>custom_widget</code> folder (your root project folder) and create a new file called <code>home.html</code>. Nah, this file will called on the previous view definition.</p>
<div class="highlight"><pre><span></span><code><span class="cp"><!DOCTYPE html></span>
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"UTF-8"</span><span class="p">></span>
<span class="p"><</span><span class="nt">title</span><span class="p">></</span><span class="nt">title</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span> <span class="s">rel="stylesheet"</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></span>
<span class="p"><</span><span class="nt">style</span><span class="p">></span>
<span class="p">.</span><span class="nc">custom-select2-widget</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="p">}</span>
<span class="w"> </span><span class="p">.</span><span class="nc">free-space</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">margin-top</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">.</span><span class="nc">toggle-handle</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="mh">#fff</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"container"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"free-space"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Custom Widget Tutorial<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
<span class="p"><</span><span class="nt">pre</span><span class="p">></span><span class="cp">{{</span> <span class="nv">request.GET</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">pre</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span><span class="p">></span>
<span class="p"><</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">""</span> <span class="na">method</span><span class="o">=</span><span class="s">"get"</span><span class="p">></span>
<span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"submit"</span> <span class="na">class</span><span class="o">=</span><span class="s">'btn btn-block'</span> <span class="na">value</span><span class="o">=</span><span class="s">"Submit"</span><span class="p">></span>
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"free-space"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://code.jquery.com/jquery-3.3.1.min.js"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</code></pre></div>
<p>The code above is for <code>home.html</code>. </p>
<p>The view not called yet when we enter the <code>http://localhost:port</code> address. To make this happen, bind this function into <code>custom_widget/custom_widget/urls.py</code></p>
<div class="highlight"><pre><span></span><code><span class="c1"># Django 2.1</span>
<span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
<span class="kn">from</span> <span class="nn">.views</span> <span class="kn">import</span> <span class="n">home</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">path</span><span class="p">(</span><span class="s1">'admin/'</span><span class="p">,</span> <span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">urls</span><span class="p">),</span>
<span class="n">path</span><span class="p">(</span><span class="s1">''</span><span class="p">,</span> <span class="n">home</span><span class="p">)</span>
<span class="p">]</span>
</code></pre></div>
<p>or</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Django 1.8</span>
<span class="kn">from</span> <span class="nn">django.conf.urls</span> <span class="kn">import</span> <span class="n">include</span><span class="p">,</span> <span class="n">url</span>
<span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">views</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># Examples:</span>
<span class="c1"># url(r'^$', 'custom_widget.views.home', name='home'),</span>
<span class="c1"># url(r'^blog/', include('blog.urls')),</span>
<span class="n">url</span><span class="p">(</span><span class="sa">r</span><span class="s1">'^admin/'</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">urls</span><span class="p">)),</span>
<span class="n">url</span><span class="p">(</span><span class="sa">r</span><span class="s1">'^$'</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">home</span><span class="p">),</span>
<span class="p">]</span>
</code></pre></div>
<p>Look, do you see the differences? Here the documentation urls (<a href="https://docs.djangoproject.com/en/2.1/topics/http/urls/">2.1</a>, <a href="https://docs.djangoproject.com/en/1.8/topics/http/urls/">1.8</a>).</p>
<p>Open your browser, and see the page will look like
<img alt="homepage" src="https://blog.ihfazh.com/images/custom-widget-1.png"></p>
<p>Next, we will make a new custom widget.</p>
<h3>Toggle</h3>
<p>The idea is to create a toggle component, that uses checkbox as original input. Also, we will not create css / javascript from scratch. We will use <a href="http://www.bootstraptoggle.com/">this</a>. Just because we use bootstrap as our base css.</p>
<p>Create <code>custom_widget/custom_widget/widgets.py</code> and write these lines.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="k">class</span> <span class="nc">ToggleWidget</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">widgets</span><span class="o">.</span><span class="n">CheckboxInput</span><span class="p">):</span>
<span class="k">class</span> <span class="nc">Media</span><span class="p">:</span>
<span class="n">css</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'all'</span><span class="p">:</span> <span class="p">(</span>
<span class="s2">"https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css"</span><span class="p">,</span> <span class="p">)}</span>
<span class="n">js</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"</span><span class="p">,)</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attrs</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">attrs</span> <span class="ow">or</span> <span class="p">{}</span>
<span class="n">default_options</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'toggle'</span><span class="p">:</span> <span class="s1">'toggle'</span><span class="p">,</span>
<span class="s1">'offstyle'</span><span class="p">:</span> <span class="s1">'danger'</span>
<span class="p">}</span>
<span class="n">options</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'options'</span><span class="p">,</span> <span class="p">{})</span>
<span class="n">default_options</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">default_options</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">attrs</span><span class="p">[</span><span class="s1">'data-'</span> <span class="o">+</span> <span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
</code></pre></div>
<p><code>class ToggleWidget(forms.widgets.CheckboxInput)</code> we sublclass the <code>forms.widgets.CheckboxInput</code>. Then,</p>
<div class="highlight"><pre><span></span><code> <span class="k">class</span> <span class="n">Media:</span>
<span class="n">css</span> = {<span class="s">'all'</span>: (
<span class="s">"https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css"</span>, )}
<span class="n">js</span> = (<span class="s">"https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"</span>,)
</code></pre></div>
<p>this will append the custom media for the <code>ToggleWidget</code>. Will wrap css to <code>link</code> tags, and <code>js</code> to <code>script</code> tags every where we use the <code>ToggleWidget</code> widget. For further information, read <a href="https://docs.djangoproject.com/en/2.1/topics/forms/media/">the documentation</a>.</p>
<p>Then, we will override the <code>__init__</code> method, expect the <code>options</code> keyword arguments, add it as <code>data-{option_key}</code> tag attribute. Finally, we call the super method. The usage of this widget is like this.</p>
<p>Lets try our new widget in the django shell.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">custom_widget</span> <span class="kn">import</span> <span class="n">widgets</span>
<span class="n">tg</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">ToggleWidget</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">tg</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'custom'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="s1">''</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">tg</span><span class="o">.</span><span class="n">media</span><span class="p">)</span>
<span class="c1"># with options</span>
<span class="n">tg</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">ToggleWidget</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="p">{</span><span class="s1">'offstyle'</span><span class="p">:</span> <span class="s1">'default'</span><span class="p">})</span>
<span class="nb">print</span><span class="p">(</span><span class="n">tg</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'custom'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="s1">''</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">tg</span><span class="o">.</span><span class="n">media</span><span class="p">)</span>
</code></pre></div>
<p><img alt="result" src="https://blog.ihfazh.com/images/custom-widget-2.png"></p>
<p>You will see, there is <code>data-toggle</code> and <code>data-offstyle</code> in the <code>input</code> tag. Also, <code>tg.media</code> is create <code>link</code> tag and <code>script</code> tag with the url we defined before.</p>
<p>Next, create the form. Create and edit <code>custom_widget/custom_widget/forms.py</code></p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">widgets</span>
<span class="k">class</span> <span class="nc">CustomWidgetForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
<span class="n">working</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span>
<span class="c1"># required must be false, otherwise you will get error when the toggle is off</span>
<span class="c1"># at least in chrome</span>
<span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">widget</span><span class="o">=</span><span class="n">widgets</span><span class="o">.</span><span class="n">ToggleWidget</span><span class="p">(</span>
<span class="n">options</span><span class="o">=</span><span class="p">{</span>
<span class="s1">'on'</span><span class="p">:</span> <span class="s1">'Yep'</span><span class="p">,</span>
<span class="s1">'off'</span><span class="p">:</span> <span class="s1">'Nope'</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div>
<p>the <code>options</code> keyword argument is based on official bootstraptoggle site and don't prefix with <code>data-</code>.</p>
<p>Use this form, in the <code>custom_widget/custom_widget/views.py</code> and your file will looks like:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">.forms</span> <span class="kn">import</span> <span class="n">CustomWidgetForm</span>
<span class="k">def</span> <span class="nf">home</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">CustomWidgetForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">CustomWidgetForm</span><span class="p">()</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'form'</span><span class="p">:</span> <span class="n">form</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span>
<span class="n">request</span><span class="p">,</span>
<span class="s1">'home.html'</span><span class="p">,</span>
<span class="n">context</span>
<span class="p">)</span>
</code></pre></div>
<p>and dont forget to add <code>{{ form }}</code> and <code>{{ form.media }}</code> in the <code>index.html</code>. And now, the <code>index.html</code> will be like</p>
<div class="highlight"><pre><span></span><code><span class="cp"><!DOCTYPE html></span>
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"UTF-8"</span><span class="p">></span>
<span class="p"><</span><span class="nt">title</span><span class="p">></</span><span class="nt">title</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span> <span class="s">rel="stylesheet"</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span> <span class="s">/</span><span class="p">></span>
<span class="p"><</span><span class="nt">style</span><span class="p">></span>
<span class="p">.</span><span class="nc">custom-select2-widget</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="p">}</span>
<span class="w"> </span><span class="p">.</span><span class="nc">free-space</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">margin-top</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">.</span><span class="nc">toggle-handle</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="mh">#fff</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"container"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"free-space"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Custom Widget Tutorial<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
<span class="p"><</span><span class="nt">pre</span><span class="p">></span><span class="cp">{{</span> <span class="nv">request.GET</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">pre</span><span class="p">></span>
<span class="p"><</span><span class="nt">hr</span><span class="p">></span>
<span class="p"><</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">""</span> <span class="na">method</span><span class="o">=</span><span class="s">"get"</span><span class="p">></span>
<span class="cp">{{</span> <span class="nv">form.as_p</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"submit"</span> <span class="na">class</span><span class="o">=</span><span class="s">'btn btn-block'</span> <span class="na">value</span><span class="o">=</span><span class="s">"Submit"</span><span class="p">></span>
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"free-space"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span>
<span class="na">src</span><span class="o">=</span><span class="s">"https://code.jquery.com/jquery-3.3.1.min.js"</span>
<span class="na">integrity</span><span class="o">=</span><span class="s">"sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="</span>
<span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="err">></span><span class="s"></script</span><span class="p">></span>
<span class="o"><</span><span class="nx">script</span><span class="w"> </span><span class="nx">src</span><span class="o">=</span><span class="s2">"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"</span><span class="w"> </span><span class="nx">integrity</span><span class="o">=</span><span class="s2">"sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"</span><span class="w"> </span><span class="nx">crossorigin</span><span class="o">=</span><span class="s2">"anonymous"</span><span class="o">></span><span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"</span> <span class="na">integrity</span><span class="o">=</span><span class="s">"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">"anonymous"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="err">></span><span class="s"></script</span><span class="p">></span>
<span class="cp">{{</span> <span class="nv">form.media</span> <span class="cp">}}</span>
<span class="o"><</span><span class="nx">script</span><span class="o">></span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</code></pre></div>
<p>Finally, your page now like this</p>
<p><img alt="toggle off" src="https://blog.ihfazh.com/images/custom-widget-3.png">
<img alt="toggle on" src="https://blog.ihfazh.com/images/custom-widget-4.png"></p>
<h3>Select2</h3>
<p>Next, We will use <code>select2</code> for the next custom widget. Bassically, it's only the <code>select</code> tag but we will append data configuration to our custom widget attributes. And also, like before, we will append css and js media. And whenever we use this widget, django will check if that media urls found or not, if not it will appended into <code>home.html</code> file. Otherwise, the media urls not appended.</p>
<p>There is two different widget, first for <code>multiple</code> select, and second for <code>single</code> select. Thus, we will create separate class for these two. And these two share same <code>Media</code> and some <code>method</code>. So, here we will create a <a href="https://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful">Mixin</a> class.</p>
<p>in <code>custom_widget/custom_widget/widgets.py</code> add</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="n">Select2Mixin</span><span class="p">():</span>
<span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="n">Media</span><span class="p">:</span>
<span class="w"> </span><span class="n">css</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s1">'all'</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="s2">"https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css"</span><span class="p">,)</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">js</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="s2">"https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'customselect2.js'</span><span class="p">)</span>
<span class="w"> </span><span class="n">def</span><span class="w"> </span><span class="n">update_attrs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">options</span><span class="p">,</span><span class="w"> </span><span class="n">attrs</span><span class="p">):</span>
<span class="w"> </span><span class="n">attrs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="o">.</span><span class="n">fix_class</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="w"> </span><span class="n">multiple</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">options</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'multiple'</span><span class="p">,</span><span class="w"> </span><span class="n">False</span><span class="p">)</span>
<span class="w"> </span><span class="n">attrs</span><span class="p">[</span><span class="s1">'data-adapt-container-css-class'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'true'</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">multiple</span><span class="p">:</span>
<span class="w"> </span><span class="n">attrs</span><span class="p">[</span><span class="s1">'multiple'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'true'</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">val</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">options</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="w"> </span><span class="n">attrs</span><span class="p">[</span><span class="s1">'data-{}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">key</span><span class="p">)]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">val</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">attrs</span>
<span class="w"> </span><span class="n">def</span><span class="w"> </span><span class="n">fix_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">attrs</span><span class="p">):</span>
<span class="w"> </span><span class="k">class_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">attrs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'class'</span><span class="p">,</span><span class="w"> </span><span class="s1">''</span><span class="p">)</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="k">class_name</span><span class="p">:</span>
<span class="w"> </span><span class="n">attrs</span><span class="p">[</span><span class="s1">'class'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'{} {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="w"> </span><span class="k">class_name</span><span class="p">,</span><span class="w"> </span><span class="s1">'custom-select2-widget'</span><span class="p">)</span>
<span class="w"> </span><span class="k">else</span><span class="p">:</span>
<span class="w"> </span><span class="n">attrs</span><span class="p">[</span><span class="s1">'class'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'custom-select2-widget'</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">attrs</span>
</code></pre></div>
<p>same as toggle widget, we specify <code>class Media</code>, but you can see a differences in <code>js=....</code>. If url is prefixes with <code>http://</code> or <code>https://</code> the django will leave it as is. Otherwise, like in the <code>customselect2.js</code> it will appended with <code>STATIC_URL</code> or <code>MEDIA_URL</code> configuration. <a href="https://docs.djangoproject.com/en/2.1/topics/forms/media/#paths-in-asset-definitions">documentation</a>.
in <code>update_attrs</code> method, we will append options into <code>attributes</code> that rendered as tag attributes. And will prefixes with <code>data-</code>.
And <code>fix_class</code> method, we add <code>custom-select2-widget</code> class, and we will use it as <code>select2</code> selector.</p>
<p>Create <code>custom_widget/static/customselect2.js</code> and fill it with</p>
<div class="highlight"><pre><span></span><code>$(document).ready(() => {
$('.custom-select2-widget').select2()
})
</code></pre></div>
<p>Its will initialize all select with class <code>custom-select2-widget</code> to be a select2 instance.</p>
<p>Now, lets create actual widget. Open <code>custom_widget/custom_widget/widgets.py</code> and write the following code</p>
<div class="highlight"><pre><span></span><code><span class="kd">class</span><span class="w"> </span><span class="nx">Select2Widget</span><span class="p">(</span><span class="nx">Select2Mixin</span><span class="p">,</span><span class="w"> </span><span class="nx">forms</span><span class="p">.</span><span class="nx">widgets</span><span class="p">.</span><span class="nx">Select</span><span class="p">):</span>
<span class="w"> </span><span class="nx">def</span><span class="w"> </span><span class="nx">__init__</span><span class="p">(</span><span class="kp">self</span><span class="p">,</span><span class="w"> </span><span class="nx">attrs</span><span class="p">=</span><span class="nx">None</span><span class="p">,</span><span class="w"> </span><span class="nx">choices</span><span class="p">=(),</span><span class="w"> </span><span class="o">*</span><span class="nx">args</span><span class="p">,</span><span class="w"> </span><span class="o">**</span><span class="nx">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="nx">attrs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">attrs</span><span class="w"> </span><span class="k">or</span><span class="w"> </span><span class="p">{}</span>
<span class="w"> </span><span class="nx">options</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">kwargs</span><span class="p">.</span><span class="nx">pop</span><span class="p">(</span><span class="err">'</span><span class="nx">options</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="p">{})</span>
<span class="w"> </span><span class="nx">new_attrs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kp">self</span><span class="p">.</span><span class="nx">update_attrs</span><span class="p">(</span><span class="nx">options</span><span class="p">,</span><span class="w"> </span><span class="nx">attrs</span><span class="p">)</span>
<span class="w"> </span><span class="nx">super</span><span class="p">().</span><span class="nx">__init__</span><span class="p">(</span><span class="nx">new_attrs</span><span class="p">)</span>
<span class="w"> </span><span class="kp">self</span><span class="p">.</span><span class="nx">choices</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">list</span><span class="p">(</span><span class="nx">choices</span><span class="p">)</span>
</code></pre></div>
<p>Note, the <code>options</code> is the <code>select2</code> options. Nothing special.</p>
<p>Then, open <code>custom_widget/custom_widget/forms.py</code> and add following code in the <code>CustomWidgetForm</code> class.</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nx">country</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">forms</span><span class="p">.</span><span class="nx">ChoiceField</span><span class="p">(</span>
<span class="w"> </span><span class="nx">choices</span><span class="p">=</span><span class="nx">countries</span><span class="p">,</span>
<span class="w"> </span><span class="nx">widget</span><span class="p">=</span><span class="nx">widgets</span><span class="p">.</span><span class="nx">Select2Widget</span>
<span class="w"> </span><span class="p">)</span>
</code></pre></div>
<p>and the <code>countries</code> variable is like </p>
<div class="highlight"><pre><span></span><code>countries = [
('id', 'Indonesia'),
('sar', 'Saudi Arabia'),
('usa', 'United Stated')
]
</code></pre></div>
<p>Reload your page and your page should like this</p>
<p><img alt="select2" src="https://blog.ihfazh.com/images/custom-widget-5.png"></p>
<hr>
<p>Let's do for <code>MultipleSelect</code>. In <code>widgets.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kd">class</span><span class="w"> </span><span class="nx">Select2MultipleWidget</span><span class="p">(</span><span class="nx">Select2Mixin</span><span class="p">,</span><span class="w"> </span><span class="nx">forms</span><span class="p">.</span><span class="nx">widgets</span><span class="p">.</span><span class="nx">SelectMultiple</span><span class="p">):</span>
<span class="w"> </span><span class="nx">def</span><span class="w"> </span><span class="nx">__init__</span><span class="p">(</span><span class="kp">self</span><span class="p">,</span><span class="w"> </span><span class="nx">attrs</span><span class="p">=</span><span class="nx">None</span><span class="p">,</span><span class="w"> </span><span class="nx">choices</span><span class="p">=(),</span><span class="w"> </span><span class="o">*</span><span class="nx">args</span><span class="p">,</span><span class="w"> </span><span class="o">**</span><span class="nx">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="nx">attrs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">attrs</span><span class="w"> </span><span class="k">or</span><span class="w"> </span><span class="p">{}</span>
<span class="w"> </span><span class="nx">options</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">kwargs</span><span class="p">.</span><span class="nx">pop</span><span class="p">(</span><span class="err">'</span><span class="nx">options</span><span class="err">'</span><span class="p">,</span><span class="w"> </span><span class="p">{})</span>
<span class="w"> </span><span class="nx">new_attrs</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kp">self</span><span class="p">.</span><span class="nx">update_attrs</span><span class="p">(</span><span class="nx">options</span><span class="p">,</span><span class="w"> </span><span class="nx">attrs</span><span class="p">)</span>
<span class="w"> </span><span class="nx">super</span><span class="p">().</span><span class="nx">__init__</span><span class="p">(</span><span class="nx">new_attrs</span><span class="p">)</span>
<span class="w"> </span><span class="kp">self</span><span class="p">.</span><span class="nx">choices</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">list</span><span class="p">(</span><span class="nx">choices</span><span class="p">)</span>
</code></pre></div>
<p>Same with Select2Widget, except now we subclass the <code>SelectMultiple</code> widget.</p>
<p>and in the <code>forms.py</code> at <code>CustomWidgetForm</code> class add <code>hobby</code> attribute:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="nx">make</span><span class="w"> </span><span class="nx">sure</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">use</span><span class="w"> </span><span class="nx">multipleCHoiceFIeld</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">you</span><span class="w"> </span><span class="nx">want</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">use</span><span class="w"> </span><span class="nx">multiple</span><span class="w"> </span><span class="nx">selection</span>
<span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="nx">otherwise</span><span class="p">,</span><span class="w"> </span><span class="nx">you</span><span class="w"> </span><span class="nx">will</span><span class="w"> </span><span class="nx">get</span><span class="w"> </span><span class="nx">an</span><span class="w"> </span><span class="nx">error</span>
<span class="w"> </span><span class="nx">hobby</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">forms</span><span class="p">.</span><span class="nx">MultipleChoiceField</span><span class="p">(</span>
<span class="w"> </span><span class="nx">choices</span><span class="p">=</span><span class="nx">hobbies</span><span class="p">,</span>
<span class="w"> </span><span class="nx">widget</span><span class="p">=</span><span class="nx">widgets</span><span class="p">.</span><span class="nx">Select2MultipleWidget</span><span class="p">(</span>
<span class="w"> </span><span class="nx">options</span><span class="p">={</span>
<span class="w"> </span><span class="err">'</span><span class="nx">placeholder</span><span class="sc">':'</span><span class="nx">Your</span><span class="w"> </span><span class="nx">placeholder</span><span class="err">'</span><span class="p">,</span>
<span class="w"> </span><span class="err">'</span><span class="nx">multiple</span><span class="err">'</span><span class="p">:</span><span class="nx">True</span><span class="p">,</span>
<span class="w"> </span><span class="err">'</span><span class="nx">maximum</span><span class="o">-</span><span class="nx">selection</span><span class="o">-</span><span class="nx">length</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">)</span>
<span class="w"> </span><span class="p">)</span>
</code></pre></div>
<p>and for <code>hobbies</code> variable fill with:</p>
<div class="highlight"><pre><span></span><code>hobbies = [
('fishing', 'Fishing'),
('writing', 'Writing'),
('coding', 'Coding')
]
</code></pre></div>
<p>Save, and reload your browser. You will get a page like this</p>
<p><img alt="select multiple" src="https://blog.ihfazh.com/images/custom-widget-6.png"></p>
<p>But, if you got a page like following, the <code>customselect2.js</code> asset not loaded properly.</p>
<p><img alt="customselect2.js not loaded" src="https://blog.ihfazh.com/images/custom-widget-7.png"></p>
<p>To fix this, go to <code>custom_widget/custom_widget/settings.py</code> and add this snippet</p>
<div class="highlight"><pre><span></span><code>STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
</code></pre></div>
<p>This will tell the django when you visit <code>host/static/customselect2.js</code> to find it from <code>static</code> folder. Save and reload, your problem will be fixed.</p>
<h3>DropZone</h3>
<p>This is the last example that I will cover in this article. In this example, I will introduce the template overriding. Ya, thats mean, you will be able to override the django template for each field.
And here is the difference between Django >= 1.11 and 1.8. In the django 1.8 you have to override the <code>render</code> method for each widget while the >= 1.11 version not. Just create a template, and pass it as <code>template_name</code> class variable.
There is another differences for django 2.1 and before it, thats the <code>json_script</code> template tag. While the <= 2.1 version didn't has the <code>json_script</code>, we still can store the json data as global variable. Thats what I will do here.
Enough for talking, lets jump into coding :</p>
<p>Edit the <code>custom_widget/custom_widget/widgets.py</code> file, and add following code for Django >= 1.11</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">DropzoneWidget</span>(<span class="n">forms</span>.<span class="n">widgets</span>.<span class="n">FileInput</span>):
<span class="n">template_name</span> = <span class="s">'forms/widgets/dropzone.html'</span>
<span class="k">class</span> <span class="n">Media:</span>
<span class="n">js</span> = (<span class="s">"https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"</span>, <span class="s">'customdz.js'</span>)
<span class="n">css</span> = {
<span class="s">'all'</span>: (<span class="s">"https://rawgit.com/enyo/dropzone/master/dist/dropzone.css"</span>,)
}
<span class="n">def</span> <span class="n">__init__</span>(<span class="nb">self</span>, <span class="n">attrs</span>=<span class="n">None</span>, <span class="n">options</span>={}):
<span class="nb">self</span>.<span class="n">options</span> = <span class="n">options</span>
<span class="n">super</span>().<span class="n">__init__</span>(<span class="n">attrs</span>)
<span class="n">def</span> <span class="n">get_context</span>(<span class="nb">self</span>, <span class="nb">name</span>, <span class="nb">value</span>, <span class="n">attrs</span>):
<span class="n">current_class</span> = <span class="n">attrs</span>.<span class="nb">get</span>(<span class="s">'class'</span>)
<span class="n">custom_class</span> = <span class="s">'custom-dropzone-widget-'</span> + <span class="nb">name</span>
<span class="k">if</span> <span class="n">current_class:</span>
<span class="n">attrs</span>[<span class="s">'class'</span>] = <span class="n">current_class</span> + <span class="s">' '</span> + <span class="n">custom_class</span>
<span class="n">else:</span>
<span class="n">attrs</span>[<span class="s">'class'</span>] = <span class="n">custom_class</span>
<span class="n">context</span> = <span class="n">super</span>(<span class="n">DropzoneWidget</span>, <span class="nb">self</span>).<span class="n">get_context</span>(<span class="nb">name</span>, <span class="nb">value</span>, <span class="n">attrs</span>)
<span class="nb">self</span>.<span class="n">options</span>.<span class="n">update</span>({
<span class="s">'class'</span>: <span class="n">custom_class</span>,
<span class="s">'paramName'</span>: <span class="nb">name</span>
})
<span class="n">context</span>[<span class="s">'options'</span>] = <span class="nb">self</span>.<span class="n">options</span>
<span class="k">return</span> <span class="n">context</span>
</code></pre></div>
<p>Bassically, the Dropzone widget is the FileInput widget but We will override the template and wrap it with dropzone structure.
Also, we will add some <code>options</code> and will pass it into template. The <code>options</code> is dropzone options. And we add a custom class for the dropzone widget, to make a css selection when initializing widget.</p>
<p>Lets talk about template! Create a new file at <code>custom_widget/templates/forms/widgets/dropzone.html</code> and add the following code</p>
<div class="highlight"><pre><span></span><code><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">'</span><span class="cp">{{</span><span class="nv">widget.attrs.class</span><span class="cp">}}</span><span class="s"> dropzone'</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">"fallback"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><input</span><span class="w"> </span><span class="na">id=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">widget.attrs.id</span> <span class="cp">}}</span><span class="s">"</span><span class="w"> </span><span class="na">type=</span><span class="s">"file"</span><span class="w"> </span><span class="na">name=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">widget.name</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"></div></span>
<span class="nt"></div></span>
<span class="cp">{{</span> <span class="nv">options</span><span class="o">|</span><span class="nf">json_script</span><span class="o">:</span><span class="nv">widget.attrs.class</span><span class="cp">}}</span>
</code></pre></div>
<p>All required attribute is at <code>widget.attrs</code> object. The <code>.fallback</code> class will be hidden if dropzone successfully initialized. Otherwise, this that will be show to you.</p>
<p><code>{{ options|json_script:widget.attrs.class }}</code> section will create <code>script</code> tag with <code>widget.attrs.class</code> id, and <code>options</code> converted to JSON object as <code>innerHTML</code>.</p>
<p>Then, create a new file at <code>custom_widget/static/customdz.js</code> and fill with</p>
<div class="highlight"><pre><span></span><code> Dropzone.autoDiscover = false;
$(document).ready(() => {
$('[id^="custom-dropzone-widget"]').each((index, element) => {
options = JSON.parse($(element).text())
className = 'div.' + options.class
console.log(options)
new Dropzone(className, options)
})
})
</code></pre></div>
<p>Don't forget to set <code>autoDiscover</code> to <code>false</code>. Then select all ids that prepended with <code>custom-dropzone-widget</code>. This will select all dropzone options. Parse the text as JSON object. Get the dropzone class, and initialize the dropzone widget. Thats the secret!</p>
<p>Lastly, edit the <code>CustomWidgetForm</code> and add the following class variable :</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="n">image</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">forms</span><span class="o">.</span><span class="n">FileField</span><span class="p">(</span>
<span class="w"> </span><span class="n">widget</span><span class="o">=</span><span class="n">widgets</span><span class="o">.</span><span class="n">DropzoneWidget</span><span class="p">(</span>
<span class="w"> </span><span class="n">options</span><span class="o">=</span><span class="p">{</span>
<span class="w"> </span><span class="s1">'url'</span><span class="p">:</span><span class="w"> </span><span class="s1">'/hello'</span><span class="p">,</span><span class="w"> </span><span class="c1"># not exists yet :D</span>
<span class="w"> </span><span class="s1">'addRemoveLinks'</span><span class="p">:</span><span class="w"> </span><span class="n">True</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'dictDefaultMessage'</span><span class="p">:</span><span class="w"> </span><span class="s1">'Upload your image here'</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">),</span>
<span class="w"> </span><span class="n">required</span><span class="o">=</span><span class="n">False</span>
<span class="w"> </span><span class="p">)</span>
</code></pre></div>
<p>save and reload. Your page should be like</p>
<p><img alt="dropzone" src="https://blog.ihfazh.com/images/custom-widget-8.png"></p>
<p>Hmmt, maybe you will get an <code>TemplateDoesNotExists</code> exception. Thats because I forget to notice you to adjust your <code>settings.py</code> file.</p>
<p>first, add </p>
<div class="highlight"><pre><span></span><code><span class="n">FORM_RENDERER</span> <span class="o">=</span> <span class="s">'django.forms.renderers.TemplatesSetting'</span>
</code></pre></div>
<p>and add <code>django.forms</code> to <code>INSTALLED_APPS</code></p>
<p>save and reload, your problem is not persist.</p>
<hr>
<p>How about Django 1.8 ? Lets handle it.</p>
<p>Edit the <code>widgets.py</code> file (I think you have remembered where this file stored :)).</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">django.template.loader</span> <span class="kn">import</span> <span class="n">render_to_string</span>
<span class="kn">from</span> <span class="nn">django.utils.safestring</span> <span class="kn">import</span> <span class="n">mark_safe</span>
<span class="k">class</span> <span class="nc">DropzoneWidget</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">widgets</span><span class="o">.</span><span class="n">FileInput</span><span class="p">):</span>
<span class="n">template_name</span> <span class="o">=</span> <span class="s1">'forms/widgets/dropzone.html'</span>
<span class="k">class</span> <span class="nc">Media</span><span class="p">:</span>
<span class="n">js</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"</span><span class="p">,</span> <span class="s1">'customdz.js'</span><span class="p">)</span>
<span class="n">css</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'all'</span><span class="p">:</span> <span class="p">(</span><span class="s2">"https://rawgit.com/enyo/dropzone/master/dist/dropzone.css"</span><span class="p">,)</span>
<span class="p">}</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attrs</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{}):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="n">options</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_context</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">attrs</span><span class="p">):</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">current_class</span> <span class="o">=</span> <span class="n">attrs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'class'</span><span class="p">)</span>
<span class="n">custom_class</span> <span class="o">=</span> <span class="s1">'custom-dropzone-widget-'</span> <span class="o">+</span> <span class="n">name</span>
<span class="k">if</span> <span class="n">current_class</span><span class="p">:</span>
<span class="n">attrs</span><span class="p">[</span><span class="s1">'class'</span><span class="p">]</span> <span class="o">=</span> <span class="n">current_class</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="n">custom_class</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">attrs</span><span class="p">[</span><span class="s1">'class'</span><span class="p">]</span> <span class="o">=</span> <span class="n">custom_class</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">build_attrs</span><span class="p">(</span><span class="n">attrs</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">update</span><span class="p">({</span>
<span class="s1">'class'</span><span class="p">:</span> <span class="n">custom_class</span><span class="p">,</span>
<span class="s1">'paramName'</span><span class="p">:</span> <span class="n">name</span>
<span class="p">})</span>
<span class="n">context</span><span class="p">[</span><span class="s1">'widget'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'name'</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span>
<span class="s1">'attrs'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">build_attrs</span><span class="p">(</span><span class="n">extra_attrs</span><span class="o">=</span><span class="n">attrs</span><span class="p">),</span>
<span class="p">}</span>
<span class="n">context</span><span class="p">[</span><span class="s1">'options'</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="p">)</span>
<span class="k">return</span> <span class="n">context</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">attrs</span><span class="o">=</span><span class="p">{}):</span>
<span class="n">context</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_context</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">attrs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">mark_safe</span><span class="p">(</span><span class="n">render_to_string</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">template_name</span><span class="p">,</span>
<span class="n">context</span><span class="p">))</span>
</code></pre></div>
<p>Can you catch the differences? The important thing is to override the <code>render</code> method yourself. Another thing is to pass a context that required in the template, so I not have to make a lot changes.</p>
<p>Then, the <code>forms/widgets/dropzone.html</code> file</p>
<div class="highlight"><pre><span></span><code><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">'</span><span class="cp">{{</span><span class="nv">widget.attrs.class</span><span class="cp">}}</span><span class="s"> dropzone'</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">"fallback"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><input</span><span class="w"> </span><span class="na">id=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">widget.attrs.id</span> <span class="cp">}}</span><span class="s">"</span><span class="w"> </span><span class="na">type=</span><span class="s">"file"</span><span class="w"> </span><span class="na">name=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">widget.name</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><script</span><span class="w"> </span><span class="na">id=</span><span class="cp">{{</span><span class="nv">widget.attrs.class</span><span class="cp">}}</span><span class="err">></span>
<span class="w"> </span><span class="s">window['</span><span class="cp">{{</span> <span class="nv">widget.attrs.class</span> <span class="cp">}}</span><span class="s">']</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="cp">{{</span> <span class="nv">options</span> <span class="o">|</span> <span class="nf">safe</span> <span class="cp">}}</span>
<span class="err"></script</span><span class="nt">></span>
</code></pre></div>
<p>Here is the trick. Pass the options as global variable. With key == <code>widget.attrs.class</code>. </p>
<p>In the <code>static/customdz.js</code></p>
<div class="highlight"><pre><span></span><code> Dropzone.autoDiscover = false;
$(document).ready(() => {
$('[id^="custom-dropzone-widget"]').each((index, element) => {
options = window[element.id]
className = 'div.' + options.class
new Dropzone(className, options)
})
})
</code></pre></div>
<p>select all tag with id prepended with <code>custom-dropzone-widget</code>. For each element, we will have an id. Then, we can get the options by selecting with <code>window[theElementId]</code>. Finally, we initialize the element to be a dropzone instance.</p>
<p>The last thing you should do is to adjust <code>forms.py</code> file like above. Save and reload your page for server that serve Django 1.8. And if you notice, you not need to change anything in the <code>settings.py</code> file.</p>
<h3>Conclusion</h3>
<p>Finally, 3 examples was done. I hope you can understand and create a new - if needed - custom django widget for your very custom application.</p>
<p>And here is some tips for creating a new custom django widget:</p>
<ol>
<li>Deep dive into <a href="https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#built-in-widgets">django widgets documentations</a>.</li>
<li>You also can go into <a href="https://github.com/django/django/blob/master/django/contrib/admin/widgets.py">django admin widgets source code</a>. Learn the widget customization from there.</li>
<li>When you need to override the template, make sure to add <code>django.forms</code> to the <code>INSTALLED_APP</code> list. And add <code>FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'</code> for django >= 1.11</li>
<li>For django 1.8, to override the template, you need to override <code>render</code> method.</li>
<li>Add the asset required as <code>Media</code> class in the widget subclass. This will add the assets if not found in the template whenever widget used.</li>
<li>To make the <code>Media</code> class actually works, add <code>{{ form.media }}</code> in your template. If not, your media assets not loaded.</li>
</ol>
<p>Thanks for reading, I hope you have a nice adventure with this examples.</p>Memahami Fungsi Enumerate2018-04-19T21:45:00+07:002018-04-19T21:45:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-04-19:/memahami-fungsi-enumerate.html<p>Setelah mengenal fungsi enumerate, yuk kita pahami alurnya dengan membuat fungsi enumerate kita sendiri. Mudah kok.</p><h1>Bismillah</h1>
<p>Di post kemarin, kita sudah mengenal apa itu fungsi enumerate dalam python dan juga bagaimana cara menggunakan dan keuntungannya. Di post sekarang, yuk kita mendalami alur kerja fungsi enumerate. Kemudian membuat kloningan fungsi enumerate ini.</p>
<h2>Alur Kerja</h2>
<p>Secara garis besar, fungsi enumerate ini me-<em>loop</em> iterable, dan mengubah dari item satuan menjadi tuple. Index pertama adalah nomor urut, dan index kedua adalah item.</p>
<p>Sebagai contoh: Ada list <code>aList</code> dengan isian berikut ini <code>['buku', 'polpen']</code>. Maka, dengan fungsi enumerate ini, item <code>buku</code> akan berubah menjadi <code>(0, 'buku')</code>.</p>
<h3>iterable ?</h3>
<p>Yang bisa di iterasi, bisa list, tuple, string.</p>
<h2>Mari kita buat</h2>
<p><strong>Disclaimer:</strong> versi asli dari fungsi enumerate adalah menggunakan keyword <code>yield</code> dan tidak menggunakan keyword <code>return</code>. Kita tidak membahas <code>yield</code> disini. Untuk memudahkan pemahaman, kita akan membuat fungsi enumerate yang mengembalikan list.</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">my_enumerate</span><span class="p">(</span><span class="n">iterable</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">start</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">:</span>
<span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">index</span><span class="p">,</span> <span class="n">x</span><span class="p">))</span>
<span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">result</span>
</code></pre></div>
<h2>Penutup</h2>
<p>Bagaimana, mudah bukan? </p>
<p>Sebagai bonus, berikut adalah versi javascript dari fungsi enumerate.</p>
<div class="highlight"><pre><span></span><code><span class="kd">function</span><span class="w"> </span><span class="nx">enumerate</span><span class="p">(</span><span class="nx">iterable</span><span class="p">,</span><span class="w"> </span><span class="nx">start</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">start</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="nx">start</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[];</span>
<span class="w"> </span><span class="nx">iterable</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="nx">index</span><span class="p">,</span><span class="w"> </span><span class="nx">item</span><span class="p">]);</span>
<span class="w"> </span><span class="nx">index</span><span class="o">++</span><span class="p">;</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">result</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Kamu mau menyumbang fungsi enumerate dalam bahasa lain ? Yuk kita diskusikan di komentar.</p>Wordpress - wp.media Javascript Object2018-04-19T05:30:00+07:002018-04-19T05:30:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-04-19:/wordpress-wp-media-javascript-object.html<p>wp.media adalah sebuah objek javascript yang digunakan oleh wordpress untuk menampilkan upload modal di wordpress admin. Sebagai contoh, ketika kamu membuka New Post, dan menekan tombol media, atau add featured image.</p><h1>Bismillah</h1>
<p><code>wp.media</code> adalah sebuah objek javascript yang wordpress gunakan untuk menampilkan upload modal di wordpress admin. Sebagai contoh, ketika kamu membuka <code>New Post</code> dan menekan tombol media, atau add featured image.
Kamu bisa membuat semisal link <code>add featured image</code> dan menampilkan upload modal dalam wordpress sendiri dengan <code>wp.media</code> ini. Artikel ini, akan membahas bagaimana kamu membuatnya.</p>
<p>Cara paling mudah, kamu buka <code>New Post</code> atau <code>New Page</code>, kemudian buka browser console kamu. Disini, saya akan mengenalkan <code>wp.media</code>, bagaimana meng-eksekusinya, dan meng-handle file / gambar yang kamu pilih di upload modal tersebut.</p>
<h2>Contoh</h2>
<p>Yuk mulai menggunakan <code>wp.media</code> ! Saya anggap kamu sudah membuka browser console. Ketikkan kode dibawah ini, setelah itu saya akan mencoba menjelaskan apa yang terjadi.</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">frame</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">wp</span><span class="p">.</span><span class="nx">media</span><span class="p">({</span>
<span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s2">"Unggah Logo Kamu"</span><span class="p">,</span>
<span class="w"> </span><span class="nx">button</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">text</span><span class="o">:</span><span class="w"> </span><span class="s2">"Gunakan media ini"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nx">multiple</span><span class="o">:</span><span class="w"> </span><span class="kc">false</span>
<span class="p">})</span>
</code></pre></div>
<p>Pertama, kita buat variable bernama <code>frame</code>. Assign <code>wp.media</code> di isi dengan properties yang di inginkan. Berikut properties <code>wp.media</code> yang saya masukkan dan keterangannya.</p>
<p>
<div class="justtable">
<table>
<thead>
<tr>
<th>No. </th>
<th> Property </th>
<th> Deskripsi</th>
</tr>
</thead>
<tbody>
<tr>
<td>1 </td>
<td> <code>title</code> </td>
<td> Sesuai nama, ini sebagai judul yang akan di tampilkan di kiri atas modal / frame yang muncul nanti</td>
</tr>
<tr>
<td>2 </td>
<td> <code>button</code> </td>
<td> Untuk override button dibawah, ketika kita telah selesai memilih image/file</td>
</tr>
<tr>
<td>3 </td>
<td> <code>multiple</code> </td>
<td> mau milih multiple image atau hanya satu saja? Karena di contoh, saya menggunakan <code>wp.media</code> untuk mengupload logo, maka cocoknya satu gambar saja.</td>
</tr>
</tbody>
</table>
</div></p>
<p>Setelah selesai menulis kode ini, kamu akan dapati, bahwa belum terjadi apa apa. <code>wp.media</code> belum menampilkan modal / frame nya. Tenang, untuk menampilkannya, kamu hanya butuh mengetikkan <code>frame.open()</code>. Daaaan...</p>
<h3>Handle Perubahan</h3>
<p>Setelah memilih milih file / gambar dari modal / frame yang dibuat oleh <code>wp.media</code>, bagaimana caranya mendapatkan file/gambar yang saya pilih?
Gunakan <code>.on('select' callback)</code> method dari <code>iframe</code> instance.</p>
<p>Perhatikan kode berikut</p>
<div class="highlight"><pre><span></span><code><span class="nx">frame</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'select'</span><span class="p">,</span><span class="w"> </span><span class="kd">function</span><span class="p">(){</span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">attachment</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">frame</span><span class="p">.</span><span class="nx">state</span><span class="p">().</span><span class="nx">get</span><span class="p">(</span><span class="s1">'selection'</span><span class="p">).</span><span class="nx">first</span><span class="p">().</span><span class="nx">toJSON</span><span class="p">()</span>
<span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">attachment</span><span class="p">)</span>
<span class="p">});</span>
</code></pre></div>
<p>perhatikan variable <code>attachment</code> diatas. Kita mengambil <code>selection</code> yang pertama, dan mengkonversi nya menjadi json objek.</p>
<p>Bila kamu ingin mengambil semua objek, atau mendapatkan array, maka gunakan <code>.all</code> sebagai ganti dari <code>.first</code>.</p>
<p>Kemudian, saya menuliskannya di terminal. Tapi kamu dapat idenya. Insya Alloh.</p>
<h2>Penutup</h2>
<p>Fuih, selesai sudah pembahasan tentang <code>wp.media</code>. Kamu dapat menggunakan <code>wp.media</code> untuk keperluan : </p>
<ul>
<li>upload logo untuk website kamu</li>
<li>upload custom banner wordpress</li>
<li>menambahkan custom images di metabox</li>
<li>dan lain sebagainya</li>
</ul>
<p>Bagaimana, sudah dapat ide untuk membuat apa?</p>Python Enumerate2018-04-18T22:36:00+07:002018-04-18T22:36:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-04-18:/python-enumerate.html<p>Mengenal enumerate dalam python. fungsi enumerate sangat powerful. Dikarenakan enumerate memudahkan kamu untuk mendapatkan index ketika melakukan loop.</p><h1>Bismillah</h1>
<p>Sudah lama tidak menulis post saya. Untuk pemanasan, saya akan membahas tentang fungsi bawaan python yang bernama <code>enumerate</code>. Fungsi <code>enumerate</code> ini akan memudahkan kamu ketika melakukan <em>looping</em> suatu <em>iterable</em> dan juga membutuhkan indexnya.</p>
<h2>Fungsi Built-in ?</h2>
<p>Di awal, saya mengatakan bahwa fungsi <code>enumerate</code> adalah fungsi bawaan. Atau dalam kata lain <em>built-in function</em>. Maksudnya adalah, sebuah fungsi yang sudah ada tanpa harus kamu import dahulu. Nah, fungsi <code>enumerate</code> ini adalah salah satunya.</p>
<h2>Penggunaa dan Contoh</h2>
<p><code>enumerate</code> menerima dua argument. Pertama sebuah objek yang bisa di iterasi/ di loop. Dan kedua adalah <code>start</code> dengan default <code>0</code>.</p>
<p><code>start</code> dalam <code>enumerate</code> ini bukan index keberapa objek ini di mulai. Akan tetapi, index <code>0</code> dalam objek ini, akan di nomori berapa ?. </p>
<h3>Contoh</h3>
<div class="highlight"><pre><span></span><code><span class="n">iterable</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'semarang'</span><span class="p">,</span> <span class="s1">'bandung'</span><span class="p">,</span> <span class="s1">'salatiga'</span><span class="p">]</span>
<span class="nb">list</span><span class="p">(</span><span class="nb">enumerate</span><span class="p">(</span><span class="n">iterable</span><span class="p">))</span>
<span class="c1"># [(0, 'semarang'), (1, 'bandung'), (2, 'salatiga')]</span>
<span class="nb">list</span><span class="p">(</span><span class="nb">enumerate</span><span class="p">(</span><span class="n">iterable</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
<span class="c1"># [(1, 'semarang'), (2, 'bandung'), (3, 'salatiga')]</span>
</code></pre></div>
<h2>Penutup</h2>
<p>Nah, itu tadi tentang <code>enumerate</code>. Sebagai bonus, berikut contoh saya menggunakan <code>enumerate</code> untuk mempermudah iterasi ketika saya membutuhkan index.</p>
<div class="highlight"><pre><span></span><code><span class="n">s</span> <span class="o">=</span> <span class="s1">'ihfazh'</span>
<span class="n">even</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">odd</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">even</span> <span class="o">+=</span> <span class="n">c</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">odd</span> <span class="o">+=</span> <span class="n">c</span>
<span class="nb">print</span><span class="p">(</span><span class="n">even</span> <span class="o">+</span> <span class="s2">" "</span> <span class="n">odd</span><span class="p">)</span>
</code></pre></div>
<p>berikut versi tanpa enumerate</p>
<div class="highlight"><pre><span></span><code><span class="n">s</span> <span class="o">=</span> <span class="s1">'ihfazh'</span>
<span class="n">even</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">odd</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">even</span> <span class="o">+=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">odd</span> <span class="o">+=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">even</span> <span class="o">+</span> <span class="s2">" "</span> <span class="n">odd</span><span class="p">)</span>
</code></pre></div>
<p>Bagaimana ? Sudah menemukan keuntungan dari <code>enumerate</code> ?</p>Eager Loading pada Eloquent2018-02-14T19:56:00+07:002018-02-14T19:56:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-02-14:/eager-loading-pada-eloquent.html<p>Mengenal tentang eager loading pada eloquent, dan apa benefit-nya.</p><h1>Bismillah</h1>
<p>Dalam eloquent query dan model yang memiliki relasi, tentunya kamu pernah mendengar <code>lazy loading</code> dan <code>eager loading</code>.</p>
<p><code>lazy loading</code> adalah meload data relasi ketika pertama kali digunakan. Dengan kata lain, ketika kamu query parent modelnya, model relasi belum di load.</p>
<p>Sedangkan <code>eager loading</code> adalah, meload relasi langsung ketika query parent dilakukan.</p>
<h2>Lazy Loading</h2>
<p>Sebagai contoh, kita punya dua table / model. <code>Post</code> dengan <code>Comment</code>. <code>Post</code> memiliki beberapa <code>Comment</code>, sedang <code>Comment</code> hanya terkait dengan satu <code>Post</code>. Jadi, relasinya adalah <code>one</code> (Post) to <code>many</code> (Comment).</p>
<p>Dalam <code>lazy loading</code>, ketika kita melakukan query seperti ini <code>Post::all()</code>, maka <code>comments</code> tidak akan keload langsung. Baru akan diload ketika kamu akses <code>comments</code> property nya.</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="nt">posts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">Post</span><span class="p">::</span><span class="nd">all</span><span class="o">();</span>
<span class="nt">foreach</span><span class="o">($</span><span class="nt">posts</span><span class="w"> </span><span class="nt">as</span><span class="w"> </span><span class="o">$</span><span class="nt">post</span><span class="o">)</span><span class="p">{</span>
<span class="w"> </span><span class="err">echo</span><span class="w"> </span><span class="err">$post->comments->count()</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>pada baris <code>echo $post->comments->count();</code>, comments baru di load.</p>
<p>Hal ini, menimbulkan masalah <code>N + 1</code> query.</p>
<p>Misalkan, jumlah dari <code>$posts</code> disitu adalah 25, maka di kode diatas, dia akan melakukan query sebanyak <code>N</code> + <code>1</code>. <code>N</code> = Jumlah posts, <code>1</code> = query pertama kali.</p>
<p>Terkadang, memang kita memerlukan <code>lazy loading</code> ini. Namun, diwaktu yang lain, kita ingin untuk tampilkan parent dengan semua relasi yang ada.</p>
<h2>Eager Loading pada Eloquent</h2>
<h3>1. Cara Dasar</h3>
<p>menggunakan method <code>with</code> dan memasukkan string sebagai argument. Contoh:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="nt">posts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">Post</span><span class="p">::</span><span class="nd">with</span><span class="o">(</span><span class="s1">'comments'</span><span class="o">)</span><span class="nt">-</span><span class="o">></span><span class="nt">get</span><span class="o">();</span>
<span class="nt">foreach</span><span class="w"> </span><span class="o">($</span><span class="nt">posts</span><span class="w"> </span><span class="nt">as</span><span class="w"> </span><span class="o">$</span><span class="nt">post</span><span class="o">)</span><span class="p">{</span>
<span class="w"> </span><span class="err">echo</span><span class="w"> </span><span class="err">$post->comments</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<h3>2. Beberapa Relasi</h3>
<p>Terkadang, relasi ke suatu table banyak. Misal Post memiliki beberapa tags, dan comments, pun authors? Kamu dapat menggunakan <code>with</code> juga, namun <code>array</code> sebagai argument. Contoh:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="nt">posts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">Post</span><span class="p">::</span><span class="nd">with</span><span class="o">(</span><span class="cp">[</span><span class="s1">'comments'</span><span class="p">,</span><span class="w"> </span><span class="s1">'tags'</span><span class="p">,</span><span class="w"> </span><span class="s1">'authors'</span><span class="cp">]</span><span class="o">)</span><span class="nt">-</span><span class="o">></span><span class="nt">get</span><span class="o">();</span>
<span class="nt">foreach</span><span class="o">($</span><span class="nt">posts</span><span class="w"> </span><span class="nt">as</span><span class="w"> </span><span class="o">$</span><span class="nt">post</span><span class="o">)</span><span class="p">{</span>
<span class="w"> </span><span class="err">echo</span><span class="w"> </span><span class="err">$post->comments</span><span class="p">;</span>
<span class="w"> </span><span class="err">echo</span><span class="w"> </span><span class="err">$posts->tags</span><span class="p">;</span>
<span class="w"> </span><span class="err">echo</span><span class="w"> </span><span class="err">$posts->authors</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<h3>3. Relasi Bersarang</h3>
<p>Nah, misal author juga memiliki kontak. Maka kamu bisa men-spesifikasikannya menggunakan <code>dot</code> syntax.</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="nt">posts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">Post</span><span class="p">::</span><span class="nd">with</span><span class="o">(</span><span class="s1">'author.contact'</span><span class="o">)</span><span class="nt">-</span><span class="o">></span><span class="nt">get</span><span class="o">();</span>
</code></pre></div>
<h3>4. Hanya Kolom Tertentu</h3>
<p>Ketiga cara diatas, akan melakukan query <code>select * from</code>. Nah, bagaimana kalau kita ingin memilih beberapa kolom saja? Kamu dapat menggunakan syntax dibawah ini:</p>
<div class="highlight"><pre><span></span><code><span class="n">table</span><span class="o">:</span><span class="n">id</span><span class="o">,</span><span class="n">col2</span>
</code></pre></div>
<blockquote>
<p>sebagai catatan, kamu harus memasukkan kolom id.</p>
</blockquote>
<p>Contoh:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="nt">posts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">Post</span><span class="p">::</span><span class="nd">with</span><span class="o">(</span><span class="s1">'author:id,username'</span><span class="o">);</span>
</code></pre></div>
<h2>Penutup</h2>
<p>Sebagai penutup, saya menggunakan teknik <code>eager loading</code> ini ketika membutuhkan array dengan seluruh bentuk, dari parent sampai childnya. Sebagai contoh dalam json :</p>
<div class="highlight"><pre><span></span><code>[
{
"id": "1",
"title": "hello world",
"comments": {
"id": '1',
"name": "hello"
}
}
]
</code></pre></div>
<p>anggep saja hanya seperti itu, tapi banyak. Dan saya tidak mungkin untuk melakukan query terpisah untuk mendapatkan data dari comments.</p>
<p>Semoga bermanfaat. Walhamduillah....</p>Menggunakan Twitter Bootstrap di Wordrpess Admin2018-02-08T06:34:00+07:002018-02-08T06:34:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-02-08:/using-twitter-bootstrap-in-wordpress-admin.html<p>Kamu adalah plugin developer, dan kamu butuh bootstrap untuk memudahkanmu styling. Tapi ternyata, ketika kamu menambahkan style ini ke wp-admin, tampilan jadi tidak seperti yang kamu harapkan. Artikel ini semoga dapat membantu kamu.</p><h1>Bismillah</h1>
<p>Kamu sedang develop wordpress plugin, dan menggunakan twitter bootstrap untuk styling. Kamu bisa saja menambahkannya dengan <code>wp_enqueue_style</code>. Css bootstrap ke-<em>load</em>, tapi tampilan admin kamu berantakan.</p>
<p>Kalau kamu melihat source code-nya css milik bootstrap dan juga wordpress, kamu akan dapati ada selector yang tabrakan. </p>
<p>Misalkan selector <code>h1,.h1</code> dari bootstrap, dia akan menimpa selector <code>h1</code>-nya milik wordpress css. Sehingga, berlakulah permasalahan perhitungan <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity">specifity</a></p>
<h2>Solusi</h2>
<p>Kamu sudah tahu permasalahannya, maka bagaimana solusinya ? Bungkus selector css milik bootstrap dengan wrapper selector. Sehingga, selector bootstrap yang tadinya hanya <code>h1, .h1</code>, menjadi <code>.bootstrap-wrapper h1, .bootstrap-wrapper .h1</code> bila kamu tentukan wrappernya adalah <code>.bootstrap-wrapper</code>.</p>
<blockquote>
<blockquote>
<p>Wrapper ini terserah kamu loh yah mau pakai apa</p>
</blockquote>
</blockquote>
<p>Sehingga, ketika kamu ingin menggunakan selector dari bootstrap ini di admin panel kamu, yang kamu butuhkan adalah, <strong>Membungkus tag yang ada, dengan div yang memiliki class atau id yang kamu tentukan di selector</strong></p>
<p>Misalkan nih, kamu ingin menggunakan <code>.modal</code> nya bootstrap. Maka, jangan langsung menulis begini : </p>
<div class="highlight"><pre><span></span><code><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">"modal"</span><span class="nt">></span>blablabla<span class="nt"></div></span>
</code></pre></div>
<p>tapi, bungkus tag tadi dengan wrapper yang sudah kamu tentukan tadi, anggap saja <code>.bootstrap-wrapper</code>.</p>
<div class="highlight"><pre><span></span><code><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">"bootstrap-wrapper"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><div</span><span class="w"> </span><span class="na">class=</span><span class="s">"modal"</span><span class="nt">></span>blablabla<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div>
<h2>Apa ada cara cepat ?</h2>
<p>Kamu bisa mengubah langsung file <code>bootstrap.css</code>, baris demi baris. Tapi, kebayangkan berapa banyak baris yang kamu perlu ubah?</p>
<p>Oleh karena itu, kamu butuh css pre processor semacam <a href="https://sass-lang.com/">sass</a> atau <a href="http://lesscss.org/">less</a> atau juga yang lainnya. </p>
<h3>Sass</h3>
<p>Pastikan kamu sudah install sass di local kamu. Karena saya kerjaan banyak menggunakan nodejs, saya install <code>node-sass</code> dengan <code>yarn add node-sass</code>. atau kamu juga bisa menginstall dengan <code>npm install node-sass</code>.</p>
<h4>Langkah :</h4>
<p>Saya ambil asumsi, bahwa kamu sudah unduh <code>bootstrap.css</code>. Selanjutnya, ubah filename menjadi <code>_bootstrap.scss</code>.</p>
<p>lalu buat file baru bernama <code>wrap-boostrap.scss</code> dan isi dengan :</p>
<div class="highlight"><pre><span></span><code><span class="p">.</span><span class="n">bootstrap</span><span class="o">-</span><span class="n">wrapper</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cp">@import</span><span class="w"> </span><span class="s2">"boostrap"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Kemudian, compile file <code>wrap-bootstrap.scss</code> dan jadikan single file css yang semua selector sudah di bungkus menggunakan <code>.bootstrap-wrapper</code>. <code>node-sass wrap-bootstrap.scss wrap.bootstrap.css</code>.</p>
<p>Baru, load file <code>wrap.bootstrap.css</code> tadi ke wordpress seperti tadi.</p>
<h3>Less</h3>
<p>Untuk installasi juga sama, kamu gunakan <code>npm</code> atau <code>yarn</code> disini. <code>npm install less</code> atau <code>yarn add less</code>.</p>
<h4>Langkah:</h4>
<p>Sama seperti tadi, asumsi saya kamu sudah unduh <code>bootstrap.css</code>. Selanjutnya, kamu buat file <code>wrap-bootstrap.less</code> dengan isi sebagai berikut :</p>
<div class="highlight"><pre><span></span><code><span class="o">.</span><span class="n">bootstrap</span><span class="o">-</span><span class="n">wrapper</span> <span class="p">{</span>
<span class="nd">@import</span> <span class="p">(</span><span class="n">less</span><span class="p">)</span> <span class="n">url</span><span class="p">(</span><span class="s1">'bootstrap.min.css'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>Setelah itu, compile dengan <code>lessc wrap-bootstrap.less wrap.bootstrap.css</code>. </p>
<p>Done.</p>
<h2>Penutup</h2>
<p>Sebagai penutup, saya ringkaskan langkah yang dapat kamu lakukan disini:</p>
<ol>
<li>Buat wrapper untuk semua css selector di dalam bootstrap</li>
<li>ketika ingin menggunakan bootstrap di html tags, kamu juga perlu membungkus dengan selector yang sudah kamu tentukan</li>
<li>untuk membuat wrapper untuk semua css selector, kamu bisa menggunakan css preprocessor yang ada semacam <code>less</code> atau <code>sass</code>.</li>
</ol>
<p>Mungkin cara ini, juga bisa digunakan untuk yang lainnya? Beritahu saya di kotak komentar bila kamu berhasil.</p>
<p><a href="https://rushfrisby.com/using-bootstrap-in-wordpress-admin-panel/">Sumber Utama</a></p>PHP Unable To Load Shared Library2018-02-02T21:30:00+07:002018-02-02T21:30:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-02-02:/php-unable-to-load-shared-library.html<p>Mungkin kamu habis upgrade php kamu dari 5 ke 7. Ketika mau cek versi, eeh, keluar banyak warning. Bisa di coba nih solusinya...</p><h1>Bismillah</h1>
<p>Kemarin, teman kerja setelah upgrade php, dia mendapatkan error / warning lah pasnya sebagai berikut: </p>
<div class="highlight"><pre><span></span><code><span class="n">PHP</span><span class="w"> </span><span class="n">Warning</span><span class="p">:</span><span class="w"> </span><span class="n">PHP</span><span class="w"> </span><span class="n">Startup</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">Unable</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="nb">load</span><span class="w"> </span><span class="n">shared</span><span class="w"> </span><span class="n">library</span><span class="w"> </span><span class="n">xxxx</span><span class="o">.</span><span class="n">so</span><span class="w"> </span><span class="o">.....</span>
</code></pre></div>
<h2>Solusi</h2>
<p>Setelah melakukan pencarian, ternyata solusi gampang. Anda hanya perlu menginstall package tersebut. Lagi lagi, saya akan mencontohkan dengan debian - ini karena saya menggunakan debian (okay, hehe) -.</p>
<p>contoh: </p>
<div class="highlight"><pre><span></span><code><span class="o">...</span><span class="p">.</span><span class="w"> </span><span class="o">/</span><span class="nx">usr</span><span class="o">/</span><span class="nx">lib</span><span class="o">/</span><span class="nx">xxxx</span><span class="o">/</span><span class="nx">xml</span><span class="p">.</span><span class="nx">so</span>
<span class="o">...</span><span class="p">.</span><span class="w"> </span><span class="o">/</span><span class="nx">usr</span><span class="o">/</span><span class="nx">lib</span><span class="o">/</span><span class="nx">xxxx</span><span class="o">/</span><span class="nx">simplexml</span><span class="p">.</span><span class="nx">so</span>
</code></pre></div>
<p>maka yang perlu anda install, nama file tanpa <code>.so</code>.</p>
<p>jadi install <code>php7.0-xml</code> dan <code>php7.0-simplexml</code></p>Composer - Requirements could not be resolved2018-02-02T20:41:00+07:002018-02-02T20:41:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-02-02:/composer-requirements-could-not-be-resolved.html<p>instalasi composer gagal karena requirements tidak didapatkan? Bila anda menggunakan linux (debian), ada kabar gembira untuk kamu.</p><h1>Bismillah</h1>
<p>Suatu ketika, kamu mengetikkan <code>composer install</code>. Kamu sudah menunggu lama, tidak ada kembalian, seakan - akan <code>composer</code> sedang <em>freeze</em>. Tiba tiba, installasi gagal, dan kamu mendapatkan keluaran kira kira begini: </p>
<div class="highlight"><pre><span></span><code><span class="nv">Problem</span><span class="w"> </span><span class="mi">1</span>:
<span class="o">-</span><span class="w"> </span><span class="nv">Installation</span><span class="w"> </span><span class="nv">request</span><span class="w"> </span><span class="k">for</span><span class="w"> </span>....<span class="w"> </span>
<span class="o">-</span><span class="w"> </span>.....<span class="w"> </span><span class="nv">requires</span><span class="w"> </span><span class="nv">xxxx</span>
</code></pre></div>
<h2>Tentang Error</h2>
<p>untuk menggunakan package yang akan di install, anda butuh menginstall package <code>xxx</code> tersebut.</p>
<h2>Solusi</h2>
<p>Perhatikan versi php anda. Saya ambil contoh disini dengan php versi 7. dan <code>xxx</code> disini adalah <code>ext-curl</code>.
Jadi, package yang perlu kamu install adalah <strong>hilangkan kata <code>ext</code> bila ada</strong> menjadi <code>php7.0-curl</code>.</p>
<p>kalau <code>xxx</code> adalah <code>ext-gd</code>, maka package yang kamu install adalah <code>php7.0-gd</code>.</p>
<h1>Penutup</h1>
<p>Dalam dunia per-codingan / software development, ketika kamu dapat pesan error dari aplikasi yang kamu tulis / tools yang kamu gunakan, jangan anggap kiamat datang yah. Perhatikan baik baik pesan error yang disampaikan. Bila belum dapat, tinggal <em>copas</em> kan line demi line error ke google search.</p>[command-line] Mencari File Sesuai Text Pattern2018-01-18T16:44:00+07:002018-01-18T16:44:00+07:00Ihfazhillahtag:blog.ihfazh.com,2018-01-18:/command-line-mencari-file-sesuai-text-pattern.html<p>Tips untuk cari file sesuai text pattern yang ada di dalamnya. Check this out..!!</p><h1>Bismillah,</h1>
<p>Ketika itu, saya harus mengubah beberapa file, karena perubahan <em>constant</em> menjadi <em>function</em>. Yang saya ingat, file yang perlu saya ubah ini banyak, tapi saya lupa dimana saja. Kalau saya harus buka satu persatu, ini akan memakan banyak waktu. Dan mungkin ada yang terluput. Jurus sakti pun keluar. Googling.</p>
<h2>Solusi</h2>
<p>Gunakan perintah berikut : </p>
<div class="highlight"><pre><span></span><code>grep -rnw "/path" -e "pattern"
</code></pre></div>
<h2>Penjelasan</h2>
<p><code>grep</code> sendiri adalah utilitas yang dapat digunakan untuk melakukan <strong>pencarian pattern</strong> di <strong>setiap file</strong>.</p>
<p><code>-e</code> adalah flag untuk <strong>matching control</strong>. Gunakan string pattern sebagai pattern. Lawannya adalah <code>-f</code>. Yaitu, gunakan file sebagai source pattern, baca <em>line by line</em></p>
<p><code>-r</code> recursive, terus ikuti pohon file kebawah (atau keatas?)</p>
<p><code>-n</code> tampilkan nomor baris.</p>
<p><code>-w</code> cocokkan satu kata.</p>
<h2>Contoh</h2>
<p><code>grep -rnw "src/scenes" -e "myUserId"</code> : cari semua file, dibawah <code>src/scenes</code> folder dan turunannya, yang cocok dengan kata <code>myUserId</code> dan tampilkan nomor baris.</p>
<p><a href="https://stackoverflow.com/questions/16956810/how-do-i-find-all-files-containing-specific-text-on-linux">Sumber</a></p>Kill Uwsgi Process2017-12-13T23:16:00+07:002017-12-13T23:16:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-12-13:/kill-stop-uwsgi-process-how-to.html<p>Uwsgi process sudah dimatikan, tapi port masih ter-pakai????</p><h1>Bismillah</h1>
<p>Saya akhir akhir ini, ada projek dan mencoba untuk menggunakan uwsgi daripada gunicorn. Semua berjalan baik sampai ketika kita butuh <code>supervisorctl restart namaapp</code>. </p>
<p>Taraa... Error ketika proses start kembali. Kenapa? </p>
<p>Setelah dilihat, ternyata port-nya belum mati, masih terpakai.</p>
<p>Habis research, maka lakukan</p>
<div class="highlight"><pre><span></span><code>fuser -k nomorport/tcp
# contoh, port yang digunakan 1234
fuser -k 1234/tcp
</code></pre></div>
<p>Sumber: https://askubuntu.com/questions/592261/how-to-exit-from-uwsgi-server-process</p>Nginx Error: connect() to /var/run/php7 .... no such file or directory2017-12-12T06:53:00+07:002017-12-12T06:53:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-12-12:/nginx-error-connect-to-varrunphp7-no-such-file-or-directory.html<p>Cara mengatasi nginx-connect-to-unix-var-run-php7-0-fpm-sock-failed-2-no-such-file-or-dir</p><p>Bismillah,</p>
<p>Error ini, saya dapati ketika mengikuti tutorial di digitalocean. Kenapa ketika saya arahkan url ke folder dimana file php saya set di nginx malah muncul <em>502</em> error? Saya check di nginx log, ternyata errornya adalah sebagaimana yang disebutkan diatas.</p>
<p>Solusinya mudah: gunakan alamat <code>unix:/var/run/php/php7.0-fpm.sock</code>.</p>
<p>Perlu di ingat, ini adalah perbedaan letak antara <code>php5-fpm</code> dengan <code>php7.0-fpm</code>.</p>
<div class="highlight"><pre><span></span><code><span class="n">Nginx</span><span class="w"> </span><span class="n">communicates</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="n">PHP</span><span class="o">-</span><span class="n">FPM</span><span class="w"> </span><span class="n">using</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">Unix</span><span class="w"> </span><span class="n">domain</span><span class="w"> </span><span class="n">socket</span><span class="o">.</span><span class="w"> </span><span class="n">Sockets</span><span class="w"> </span><span class="n">map</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="n">on</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">filesystem</span><span class="p">,</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">our</span><span class="w"> </span><span class="n">PHP</span><span class="w"> </span><span class="mi">7</span><span class="w"> </span><span class="n">installation</span><span class="w"> </span><span class="n">uses</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">default</span><span class="p">:</span>
<span class="n">PHP</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">run</span><span class="o">/</span><span class="n">php5</span><span class="o">-</span><span class="n">fpm</span><span class="o">.</span><span class="n">sock</span>
<span class="n">PHP</span><span class="w"> </span><span class="mi">7</span><span class="w"> </span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">run</span><span class="o">/</span><span class="n">php</span><span class="o">/</span><span class="n">php7</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">fpm</span><span class="o">.</span><span class="n">sock</span>
</code></pre></div>
<p>https://stackoverflow.com/questions/40059745/nginx-connect-to-unix-var-run-php7-0-fpm-sock-failed-2-no-such-file-or-dir</p>
<p>Semoga membantu...</p>#sqlalchemytips - 2 Foreignkey (Atau Lebih) Antara 2 Table2017-05-24T10:55:00+07:002017-05-24T10:55:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-24:/sqlalchemytips-2-foreignkey-atau-lebih-antara-2-table.html<p>Tips untuk mengatasi error AmbiguousForeignKeyError dalam sqlalchemy ketika mempunyai 2 atau lebih foreignkey dari satu table yang me-link ke table yang lainnya</p><h1>Bismillah,</h1>
<h2>Masalah</h2>
<p>Saat saya mendesain database, ternyata ada 2 kolom di suatu table yang
berhubungan dengan satu table yang lainnya. </p>
<p>Sebagai contoh (ini contoh dari project yang sedang saya kerjakan). Saya punya dua table <strong>Kajian</strong> dan
<strong>User</strong>. Setiap <strong>Kajian</strong> memiliki 2 kolom yang kedua duanya ini berkaitan /
memiliki <code>ForeignKey</code> menuju table <strong>User</strong>. Yaitu <strong>ustadz</strong> dan
<strong>koordinator</strong>. Maka, berikut Model table yang saya buat.</p>
<blockquote>
<p>catatan: saya menggunakan <code>flask-sqlalchemy</code> sedangkan dokumentasi yang saya
gunakan adalah milik <code>sqlalchemy</code>. Secara garis besar sama.</p>
</blockquote>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">200</span><span class="p">))</span>
<span class="k">class</span> <span class="nc">Kajian</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">judul</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">200</span><span class="p">))</span>
<span class="n">koordinator_id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">db</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.id'</span><span class="p">))</span>
<span class="n">koordinator</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s1">'User'</span><span class="p">,</span>
<span class="n">backref</span><span class="o">=</span><span class="n">db</span><span class="o">.</span><span class="n">backref</span><span class="p">(</span><span class="s1">'koordinator_kajian'</span><span class="p">))</span>
<span class="n">ustadz_id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">db</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.id'</span><span class="p">))</span>
<span class="n">ustadz</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s1">'User'</span><span class="p">,</span>
<span class="n">backref</span><span class="o">=</span><span class="n">db</span><span class="o">.</span><span class="n">backref</span><span class="p">(</span><span class="s1">'ustadz_kajian'</span><span class="p">))</span>
</code></pre></div>
<p>Ringkasnya, kode diatas kita mendefiniskan 2 <code>ForeignKey</code> di table <strong>Kajian</strong>
menuju table <strong>User</strong>.</p>
<p>Masalahnya, ketika kode diatas di jalankan, maka akan keluar error <code>AmbiguousForeignKeyError</code>. Kenapa?
karena defaultnya, fungsi <code>relationship()</code> akan mencari -secara otomatis-
<code>ForeignKey</code> antara dua table dari kolom yang didefinisikan sebagai
<code>ForeignKey</code>. Jadi, baik di <code>koordinator</code> dan <code>ustadz</code>, maka keduanya akan sama
sama mencari <code>ForeignKey</code> yang menghubungkan table ini ke table <code>User</code>.
<code>relationship()</code> ini ternyata menemukan ada 2 <code>ForeignKey</code> menuju <code>user.id</code>,
sehingga keluarlah error ini.</p>
<h2>Solusi</h2>
<p>Tambahkan <code>foreign_keys</code> argument ke <code>relationship()</code> yang berisi <code>list</code> untuk
menentukan, <code>ForeignKey</code> mana yang akan dipakai. Mana yang untuk <code>ustadz</code> dan
mana yang untuk <code>koordinator</code>.</p>
<p>Lebih jelasnya, perhatikan kode berikut.</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Kajian</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="o">....</span>
<span class="n">koordinator</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s1">'User'</span><span class="p">,</span> <span class="n">foreign_keys</span><span class="o">=</span><span class="p">[</span><span class="n">koordinator_id</span><span class="p">],</span>
<span class="n">backref</span><span class="o">=</span><span class="n">db</span><span class="o">.</span><span class="n">backref</span><span class="p">(</span><span class="s1">'koordinator_kajian'</span><span class="p">))</span>
<span class="o">....</span>
<span class="n">ustadz</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s1">'User'</span><span class="p">,</span> <span class="n">foreign_keys</span><span class="o">=</span><span class="p">[</span><span class="n">ustadz_id</span><span class="p">],</span>
<span class="n">backref</span><span class="o">=</span><span class="n">db</span><span class="o">.</span><span class="n">backref</span><span class="p">(</span><span class="s1">'ustadz_kajian'</span><span class="p">))</span>
</code></pre></div>
<p>Perhatikan, di kode tadi, kita menentukan mana <code>ForeignKey</code> untuk
<code>relationship</code>-nya <code>ustadz</code>. Dan mana yang miliknya <code>koordinator</code>. Menggunakan
argument bernama <code>foreign_keys</code> di fungsi <code>relationship</code>.</p>
<h2>Kesimpulan</h2>
<p><code>relationship</code> secara default akan mencari kolom mana yang digunakan sebagai
relasi ke table yang di tentukan di fungsi ini. Ini akan menjadi masalah ketika
ada 2 atau lebih relasi yang ada di table ini. Di artikel ini satu di antara
contohnya.</p>
<p>Sebagai tambahan bacaan, pembaca bisa membacanya lebih lengkap di
dokumentasinya Sqlalchemy bagian Configuring How Relationship Joins.</p>
<p>Semoga bermanfaat, dan semoga dapat terfahami.</p>Pymysql Internal Error Incorrect String Value2017-05-21T21:03:00+07:002017-05-21T21:03:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-21:/pymysql-internal-error-incorrect-string-value.html<p>tips sederhana mengatasi internal error incorrect string value ketika memasukkan arabic value ke table dalam mysql</p><h1>Bismillah</h1>
<p>Baru kali ini saya menyentuh mysql, dan ingin membuat table yang berisi kolom
diantaranya adalah <code>post</code>. Kolom <code>post</code> ini harus bisa menyimpan unicode value,
diantaranya adalah arabic.</p>
<p>Ketika <em>testing</em> sampai ke table <code>post</code> untuk blog, masalah ini bermula. Saya
test menggunakan kata مقدمة dan... </p>
<div class="highlight"><pre><span></span><code><span class="n">InternalError</span><span class="p">:</span> <span class="p">(</span><span class="mi">1366</span><span class="p">,</span> <span class="s2">"Incorrect string value:</span>
</code></pre></div>
<h2>Solusi</h2>
<p>Ini solusi saya, buat ulang databasenya dengan <em>menge-set</em> encoding yang
sesuai. Karena saya masih dalam tahap testing. Hehe.</p>#sqlalchemytips - Create Database Ketika Tidak Ditemukan2017-05-21T20:47:00+07:002017-05-21T20:47:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-21:/sqlalchemytips-create-database-ketika-tidak-ditemukan.html<p>Membuat database ketika database tidak ditemukan</p><h1>Bismillah,</h1>
<p>Saat saya bekerja menggunakan <code>sqlalchemy</code>dan <code>mysql</code>, kemudian database belum
dibuat, maka saya harus masuk ke mysql console dan mengetikkan perintah <code>CREATE
DATABASE inidatabase</code>. Setelah itu baru bisa menggunakannya lewat <code>sqlalchemy</code></p>
<p>Namun, masalahnya ketika saya ingin mengubah database url, saya harus
<em>re-create</em> lagi dong? </p>
<h2>Tipsnya</h2>
<p>Gunakan kombinasi <code>database_exists</code> dan <code>create_database</code> dari
<code>sqlalchemy_utils</code> package.</p>
<p>Berikut langkahnya :</p>
<ol>
<li>Install <code>sqlalchemy_utils</code></li>
<li>check kalau database sudah ada atau tidak menggunakan <code>database_exists</code></li>
<li>buat database kalau tidak ada menggunakan <code>create_database</code></li>
</ol>
<p>Lihat kode berikut</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">sqlalchemy_utils.functions</span> <span class="kn">import</span> <span class="n">database_exists</span><span class="p">,</span> <span class="n">create_database</span>
<span class="n">db</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">engine</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">database_exists</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">):</span>
<span class="n">create_database</span><span class="p">(</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
</code></pre></div>
<p>Perhatikan, contoh diatas saya menggunakan <code>flask_sqlalchemy</code>. Saya dapatkan
url database menggunakan <code>engine.url</code>.</p>
<h2>Kesimpulan</h2>
<p>Dengan <code>sqlalchemy_utils</code> ini, saya menjadi sangat terbantu. Sehingga saya
tidak perlu <em>re-create</em> database secara manual lagi setiap <strong>harus</strong> pindah
database/ pindah tempat.</p>
<p>Semoga bermanfaat.</p>Urlparse - Parse Url Menjadi Beberapa Bagian2017-05-15T09:32:00+07:002017-05-15T09:32:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-15:/urlparse-parse-url-menjadi-beberapa-bagian.html<p>Memudahkan tugas parsing url di python3 maupun python2</p><h1>Bismillah</h1>
<p>Pembahasan kita kali ini akan khusus ke sebuah tool yang bernama <code>urlparse</code> dan
<code>urlunparse</code>. </p>
<h2>urlparse</h2>
<p>ini berguna untuk keperluan membagi url yang kita berikan menjadi 6
bagian. Perhatikan contoh dan table berikut. Taruhlah kita memiliki url seperti
berikut
<code>http://user:pass@NetLoc:80/path;parameters/path2;parameters2?query=argument#fragment</code></p>
<p>maka, hasilnya kurang lebih sebagai berikut:</p>
<table>
<thead>
<tr>
<th>Bagian</th>
<th>Index</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>scheme</td>
<td>0</td>
<td>http</td>
</tr>
<tr>
<td>netloc</td>
<td>1</td>
<td>user:pass@NetLoc:80</td>
</tr>
<tr>
<td>path</td>
<td>2</td>
<td>/path;parameters/path2;parameters2</td>
</tr>
<tr>
<td>params</td>
<td>3</td>
<td>params</td>
</tr>
<tr>
<td>query</td>
<td>4</td>
<td>query</td>
</tr>
<tr>
<td>fragment</td>
<td>5</td>
<td>fragment</td>
</tr>
<tr>
<td>username</td>
<td></td>
<td>user</td>
</tr>
<tr>
<td>password</td>
<td></td>
<td>pass</td>
</tr>
<tr>
<td>hostname</td>
<td></td>
<td>netloc</td>
</tr>
<tr>
<td>port</td>
<td></td>
<td>80</td>
</tr>
</tbody>
</table>
<p><code>urlparse</code> dan <code>urlunparse</code> merupakan library yang sangat berguna bagi kita
yang berurusan dengan permasalahan url. Dan library ini adalah library
<code>builtin</code>, sehingga kita tidak perlu lagi menginstall library tambahan.untuk bagian yang tidak ada indexnya, maka kita tidak dapat memanggilnya
menggunakan index. Akan tetapi menggunakan notasi dot. </p>
<p>Perhatikan contoh berikut (masih menggunakan url di atas)</p>
<div class="highlight"><pre><span></span><code><span class="n">url</span> <span class="o">=</span>
<span class="s2">"http://user:pass@NetLoc:80/path;parameters/path2;parameters2?query=argument#fragment"</span>
<span class="n">parsed</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="err">`</span><span class="n">urlparse</span><span class="err">`</span> <span class="n">dan</span> <span class="err">`</span><span class="n">urlunparse</span><span class="err">`</span> <span class="n">merupakan</span> <span class="n">library</span> <span class="n">yang</span> <span class="n">sangat</span> <span class="n">berguna</span> <span class="n">bagi</span> <span class="n">kita</span>
<span class="n">yang</span> <span class="n">berurusan</span> <span class="n">dengan</span> <span class="n">permasalahan</span> <span class="n">url</span><span class="o">.</span> <span class="n">Dan</span> <span class="n">library</span> <span class="n">ini</span> <span class="n">adalah</span> <span class="n">library</span>
<span class="err">`</span><span class="n">builtin</span><span class="err">`</span><span class="p">,</span> <span class="n">sehingga</span> <span class="n">kita</span> <span class="n">tidak</span> <span class="n">perlu</span> <span class="n">lagi</span> <span class="n">menginstall</span> <span class="n">library</span> <span class="n">tambahan</span><span class="err">`</span><span class="n">urlparse</span><span class="err">`</span> <span class="n">dan</span> <span class="err">`</span><span class="n">urlunparse</span><span class="err">`</span> <span class="n">merupakan</span> <span class="n">library</span> <span class="n">yang</span> <span class="n">sangat</span> <span class="n">berguna</span> <span class="n">bagi</span> <span class="n">kita</span> <span class="n">yang</span> <span class="n">berurusan</span> <span class="n">dengan</span> <span class="n">permasalahan</span> <span class="n">url</span><span class="o">.</span> <span class="n">Dan</span> <span class="n">library</span> <span class="n">ini</span> <span class="n">adalah</span> <span class="n">library</span> <span class="err">`</span><span class="n">builtin</span><span class="err">`</span><span class="p">,</span> <span class="n">sehingga</span> <span class="n">kita</span> <span class="n">tidak</span> <span class="n">perlu</span> <span class="n">lagi</span> <span class="n">menginstall</span> <span class="n">library</span> <span class="n">tambahan</span><span class="err">`</span><span class="n">urlparse</span><span class="err">`</span> <span class="n">dan</span> <span class="err">`</span><span class="n">urlunparse</span><span class="err">`</span> <span class="n">merupakan</span> <span class="n">library</span> <span class="n">yang</span> <span class="n">sangat</span> <span class="n">berguna</span> <span class="n">bagi</span> <span class="n">kita</span> <span class="n">yang</span> <span class="n">berurusan</span> <span class="n">dengan</span> <span class="n">permasalahan</span> <span class="n">url</span><span class="o">.</span> <span class="n">Dan</span> <span class="n">library</span> <span class="n">ini</span> <span class="n">adalah</span> <span class="n">library</span> <span class="err">`</span><span class="n">builtin</span><span class="err">`</span><span class="p">,</span> <span class="n">sehingga</span> <span class="n">kita</span> <span class="n">tidak</span> <span class="n">perlu</span> <span class="n">lagi</span> <span class="n">menginstall</span> <span class="n">library</span> <span class="n">tambahan</span><span class="err">`</span><span class="n">urlparse</span><span class="err">`</span> <span class="n">dan</span> <span class="err">`</span><span class="n">urlunparse</span><span class="err">`</span> <span class="n">merupakan</span> <span class="n">library</span> <span class="n">yang</span> <span class="n">sangat</span> <span class="n">berguna</span> <span class="n">bagi</span> <span class="n">kita</span> <span class="n">yang</span> <span class="n">berurusan</span> <span class="n">dengan</span> <span class="n">permasalahan</span> <span class="n">url</span><span class="o">.</span> <span class="n">Dan</span> <span class="n">library</span> <span class="n">ini</span> <span class="n">adalah</span> <span class="n">library</span> <span class="err">`</span><span class="n">builtin</span><span class="err">`</span><span class="p">,</span> <span class="n">sehingga</span> <span class="n">kita</span> <span class="n">tidak</span> <span class="n">perlu</span> <span class="n">lagi</span> <span class="n">menginstall</span> <span class="n">library</span> <span class="n">tambaha</span><span class="err">`</span><span class="n">urlparse</span><span class="err">`</span> <span class="n">dan</span> <span class="err">`</span><span class="n">urlunparse</span><span class="err">`</span> <span class="n">merupakan</span> <span class="n">library</span> <span class="n">yang</span> <span class="n">sangat</span> <span class="n">berguna</span> <span class="n">bagi</span> <span class="n">kita</span> <span class="n">yang</span> <span class="n">berurusan</span> <span class="n">dengan</span> <span class="n">permasalahan</span> <span class="n">url</span><span class="o">.</span> <span class="n">Dan</span> <span class="n">library</span> <span class="n">ini</span> <span class="n">adalah</span> <span class="n">library</span> <span class="err">`</span><span class="n">builtin</span><span class="err">`</span><span class="p">,</span> <span class="n">sehingga</span> <span class="n">kita</span> <span class="n">tidak</span> <span class="n">perlu</span> <span class="n">lagi</span> <span class="n">menginstall</span> <span class="n">library</span> <span class="n">tambahan</span><span class="o">.</span><span class="n">n</span><span class="o">....</span><span class="c1"># kita memanggil dengan index, hanya bisa sampai 5</span>
<span class="nb">print</span><span class="p">(</span><span class="n">parsed</span><span class="p">[</span><span class="mi">8</span><span class="p">])</span> <span class="c1"># index error, gunakan notasi dot</span>
<span class="nb">print</span><span class="p">(</span><span class="n">parsed</span><span class="o">.</span><span class="n">port</span><span class="p">)</span>
</code></pre></div>
<p>Untuk hasil yang dihasilkan oleh <code>urlparse</code> maka dia <code>readonly</code>, maknanya tidak
bisa diubah ubah. Jadi, ketika kita ingin mengubah suatu bagian dari yang
disebutkan diatas, netloc misalnya (sebagaimana dalam studi kasus yang akan
datang), maka kita perlu untuk mengubahnya menjadi
list dahulu.</p>
<h2>urlunparse</h2>
<p>adapun <code>urlunparse</code> adalah sebaliknya. Yaitu membungkus pecahan yang dihasilkan
oleh <code>urlparse</code> menjadi url utuh. Atau bisa juga digunakan untuk membungkus
list/tuple dengan isi dengan urutan sebagaimana <code>urlparse</code> mengurutkannya.</p>
<h2>Beda python2 dan python3</h2>
<p>Hanya di peletakan library saja. Di python2 library <code>urlparse</code> dan <code>urlunparse</code> berada di
<code>urlparse.urlparse</code> dan <code>urlparse.urlunparse</code>. Sedangkan di python3 dia terletak
di <code>urllib.parse.urlparse</code> dan <code>urllib.parse.urlunparse</code>.</p>
<h2>Studi Kasus</h2>
<p>url =
http://3.bp.blogspot.com/-ROyYC5sfXeg/VB5aAa2iLWI/AAAAAAAABac/KX3hgNJGcCo/s1600/Gambar%2BPemandangan%2BAlam%2BTerindah%2Bdi%2BDunia%2BPuncak%2BGung%2BBukit%2BHijau%2BCantik.jpg</p>
<p>jadikan url diatas menjadi
http://i0.wp.com/3.bp.blogspot.com/-ROyYC5sfXeg/VB5aAa2iLWI/AAAAAAAABac/KX3hgNJGcCo/s1600/Gambar%2BPemandangan%2BAlam%2BTerindah%2Bdi%2BDunia%2BPuncak%2BGung%2BBukit%2BHijau%2BCantik.jpg</p>
<p>Yuk, perhatikan analisa dan langkah berikut:</p>
<p>Perubahan diatas, berada di bagian <code>netloc</code>. Dengan menambahkan <code>i0.wp.com/</code> di
depannya. Dan <code>netloc</code> ini berada di index 1. Karena <code>ParseResult</code> object
adalah <strong>readonly</strong>, maka kita perlu mengubah hasilnya menjadi list. Kemudian
kita ubah isi dari index 1 menjadi yang di inginkan. Setelah itu baru
kembalikan menjadi url utuh.</p>
<p>Jadi secara ringkas, langkah yang akan kita lakukan seperti ini:</p>
<ol>
<li>parse url (gunakan <code>urlparse</code>)</li>
<li>ubah menjadi list (gunakan <code>list</code>)</li>
<li>ubah index 1</li>
<li>unparse lagi (gunakan <code>urlunparse</code>)</li>
</ol>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlparse</span><span class="p">,</span> <span class="n">urlunparse</span>
<span class="n">url</span> <span class="o">=</span>
<span class="s2">"http://3.bp.blogspot.com/-ROyYC5sfXeg/VB5aAa2iLWI/AAAAAAAABac/KX3hgNJGcCo/s1600/Gambar%2BPemandangan%2BAlam%2BTerindah%2Bdi%2BDunia%2BPuncak%2BGung%2BBukit%2BHijau%2BCantik.jpg"</span>
<span class="n">parsed</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">parsed</span><span class="o">.</span><span class="n">netloc</span> <span class="c1"># 3.bp.blogspot.com</span>
<span class="n">parsed</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># 3.bp.blogspot.com</span>
<span class="n">parsed_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">parsed</span><span class="p">)</span>
<span class="n">parsed_list</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'i0.wp.com/'</span> <span class="o">+</span> <span class="n">parsed_list</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">unparsed</span> <span class="o">=</span> <span class="n">urlunparse</span><span class="p">(</span><span class="n">parsed_list</span><span class="p">)</span>
</code></pre></div>
<h2>Kesimpulan</h2>
<p><code>urlparse</code> dan <code>urlunparse</code> merupakan library yang sangat berguna bagi kita
yang berurusan dengan permasalahan url. Dan library ini adalah library
<code>builtin</code>, sehingga kita tidak perlu lagi menginstall library tambahan.</p>#bashtips - Riwayat Perintah (History Dan Fc)2017-05-07T20:16:00+07:002017-05-07T20:16:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-07:/bashtips-riwayat-perintah-history-dan-fc.html<p>Mengatasi <em>lupa</em> perintah yang pernah kita jalankan di linux.</p><h1>Bismillah</h1>
<p>Seringkali saya tidak ingat, alamat IP server yang saya gunakan untuk bekerja. Sehingga, sering kali saya harus menekan tombol panah atas berkali kali sampai saya dapatkan perintah yang pernah saya jalankan.</p>
<p>Di terminal linux sendiri, ada fasilitas penyimpanan riwayat perintah yang kita pernah jalankan. Diantaranya tadi, dengan menekan panah atas beberapa kali.</p>
<p>Akan tetapi, cara ini kurang efisien. Terlebih ketika perintah ini sudah kita jalankan setelah waktu berselang lama. </p>
<h2>Perintah <code>history</code></h2>
<p>Perintah <code>history</code> memungkinkan anda untuk melihat riwayat perintah yang pernah anda tuliskan. Anda juga dapat menghapus riwayat anda, baik keseluruhan maupun pada baris tertentu.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">history</span><span class="w"> </span><span class="c1"># ini me-list semua riwayat</span>
$<span class="w"> </span><span class="nb">history</span><span class="w"> </span><span class="m">10</span><span class="w"> </span><span class="c1"># me-list 10 riwayat terakhir</span>
$<span class="w"> </span><span class="nb">history</span><span class="w"> </span>-d<span class="w"> </span><span class="m">10</span><span class="w"> </span><span class="c1"># menghapus riwayat baris ke sepuluh</span>
$<span class="w"> </span><span class="nb">history</span><span class="w"> </span>-c<span class="w"> </span><span class="c1"># menghapus semua riwayat</span>
</code></pre></div>
<p>Untuk perintah lainnya, anda dapat melihatnya di <code>man history</code> atau <code>history --help</code></p>
<h2>Perintah <code>fc</code></h2>
<p>Ada lagi perintah lain yang berkaitan dengan riwayat perintah yang pernah kita jalankan. Yaitu <code>fc</code>. Berangkat dari rasa penasaran saya ketika mengetikkan <code>fc</code> kemudian tab (saya waktu itu sedang berurusan dengan font, karena font commandnya didahului dengan <code>fc-</code>), maka saya cari dengan <code>man fc</code>. Tidak ada. Oke, <code>fc --help</code>. Nah, akhirnya sangat berguna juga perintah ini.</p>
<p>Oke, balik lagi.</p>
<p>Perintah <code>fc</code> ini digunakan untuk melist atau mengedit, atau malah menjalankan ulang perintah yang pernah kita lakukan.</p>
<p>Bagaimana? Misal kita lupa nomor IP, dan butuh ssh ulang. Maka kita lihat list riwayat, kemudian kita jalankan ulang lagi tanpa menulis / copas perintah itu. </p>
<p>Perhatikan perintah - perintah berikut</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">fc</span><span class="w"> </span>-l<span class="w"> </span><span class="c1"># untuk menampilkan riwayat default 17 baris</span>
$<span class="w"> </span><span class="nb">fc</span><span class="w"> </span>-l<span class="w"> </span><span class="m">100</span><span class="w"> </span><span class="c1"># untuk menampilkan 100 baris riwayat </span>
$<span class="w"> </span><span class="nb">fc</span><span class="w"> </span><span class="m">100</span><span class="w"> </span><span class="c1"># meng-edit baris ke 100, dan ketika kita tutup akan kita akan menjalankan perintah tersebut</span>
$<span class="w"> </span><span class="nb">fc</span><span class="w"> </span>-s<span class="w"> </span><span class="m">100</span><span class="w"> </span><span class="c1"># jalankan kembali perintah di baris ke 100 tanpa harus mengedit</span>
</code></pre></div>
<p>Asyik bukan?</p>
<h2>Kesimpulan</h2>
<p>Dua perintah diatas, kurang lebih sama fungsinya. Akan tetapi, perintah <code>fc</code> mempunyai kelebihan yaitu <strong>manipulasi perintah</strong></p>
<p>Namun, yang saya lakukan untuk masalah diatas adalah:</p>
<ol>
<li>Cari perintah yang kurang lebih sama dengan yang dahulu saya jalankan. Dalam hal ini ssh.</li>
<li>Jalankan line tersebut dengan <code>fc -s n</code> dimana <code>n</code> adalah baris perintah itu bersemayam.</li>
</ol>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">history</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>ssh<span class="w"> </span>--><span class="w"> </span>output:<span class="w"> </span><span class="m">100</span><span class="w"> </span>ssh<span class="w"> </span>root@nomorIP,<span class="w"> </span>misalnya
$<span class="w"> </span><span class="nb">fc</span><span class="w"> </span>-s<span class="w"> </span><span class="m">100</span>
</code></pre></div>
<p>bagaimana? Membantu bukan ? </p>#GitTips - Langkah Ketika File Terhapus2017-05-07T11:26:00+07:002017-05-07T11:26:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-05-07:/gittips-langkah-ketika-file-terhapus.html<p>Kamu lupa menghapus file, padahal file tersebut sangat penting. Bila kamu pakai git, maka ada kabar gembira untukmu.</p><h1>Bismillah</h1>
<p>Dhuarr !!</p>
<p>Tiba tiba kamu tersadar, ternyata kamu tidak sengaja <em>ngetikkan</em> perintah <code>rm *</code>. Dan apa yang terjadi? Kamu sudah menghapus semua file yang ada di folder kamu bekerja. Padahal, pekerjaan-mu sudah hampir selesai.</p>
<p>Pernahkah kamu pusing karena kejadian ini?</p>
<p>Bila kamu menggunakan <code>git</code>, maka kamu punya kabar gembira.</p>
<h2>Langkah</h2>
<ol>
<li>Buat <code>branch</code> baru</li>
<li><code>commit</code>-kan perubahan yang tidak diinginkan tersebut</li>
<li>pindah ke <code>branch</code> master/yang kamu sedang bekerja</li>
<li>hapus <code>branch</code> baru tersebut</li>
</ol>
<h2>Ilustrasi</h2>
<p>Misalkan, kamu sedang bekerja di <em>branch</em> <code>master</code>, dan tidak sengaja kamu mengetikkan perintah diatas. Maka, </p>
<div class="highlight"><pre><span></span><code><span class="err">$</span> <span class="n">git</span> <span class="n">checkout</span> <span class="o">-</span><span class="n">b</span> <span class="n">tidak_diinginkan</span>
<span class="err">$</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">am</span> <span class="s2">"ini commit penghapusan yang tidak diinginkan"</span>
<span class="err">$</span> <span class="n">git</span> <span class="n">checkout</span> <span class="n">master</span>
<span class="err">$</span> <span class="n">git</span> <span class="n">branch</span> <span class="o">-</span><span class="n">D</span> <span class="n">tidak_diinginkan</span>
</code></pre></div>
<p>nah, akhirnya kamu sudah kembali ke <em>stage</em> dimana kamu belum menghapus file tersebut.</p>
<h2>Kesimpulan</h2>
<p>Ini, adalah langkah sederhana yang bisa kamu lakukan ketika kamu kelupaan menghapus atau mengedit file dan ingin mengembalikan seperti sedia kala sebelum perubahan tersebut.</p>Generate File Patch Dari Github Dan Apply Patch2017-04-30T16:44:00+07:002017-04-30T16:44:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-04-30:/generate-file-patch-dari-github-dan-apply-patch.html<p>Tips add buat file patch dari github dan apply</p><h1><strong>Bismillah</strong></h1>
<h2>Pendahuluan</h2>
<p>Dengan <a href="http://github.com">github</a>, dengan mudah kita bisa membuat file <code>patch</code> dari sebuah <code>pull requests</code>. Terlebih, ketika si-<em>empunya</em> repository belum menyetujui <code>PR</code> ini, tapi kamu sudah <em>kesusu</em> untuk memakai fitur yang ada di <code>PR</code> ini.</p>
<p>Sebagai contoh, pada projek <a href="https://github.com/audreyr/cookiecutter">cookiecutter</a>, ada fitur yang ditawarkan di versi terakhir (<code>1.5.x</code>), yaitu <strong>kita dapat menambahkan <code>jinja2</code> extensions dengan mengkonfigurasikan di <code>cookiecutter.json</code></strong>. Namun sayangnya, <code>jinja2</code> extension ini harus terinstall pada <em>system-wide</em>. Kalau kita buat sendiri, taruh di direktori template, maka akan ada pesan <code>ImportError</code>. <em>Alhamdulillah</em>, ada yang mengirimkan <code>PR</code> <a href="https://github.com/audreyr/cookiecutter/pull/892">ini</a>. Nah, <code>PR</code> ini belum di setujui oleh bu audreyr, tapi saya harus pakai pr ini. </p>
<h2>How To ?</h2>
<p>Caranya: </p>
<ol>
<li>tambahkan <code>.patch</code> ke akhir alamat <code>PR</code> tadi. </li>
<li>kemudian <strong>unduh</strong> file tersebut. </li>
<li>Dan Jalankan perintah berikut <code>git am patchfile</code></li>
</ol>
<p>Mudah bukan?</p>
<h2>Akhirnya</h2>
<p>Pada akhirnya, untuk menggunakannya saya install aplikasi ini dengan cara:</p>
<ol>
<li>clone git repo tersebut</li>
<li>patch dengan file tadi</li>
<li>install dengan pip ke virtual environment project kita tadi</li>
</ol>
<p>Sedikit membantu bukan ? </p>[Telegram Bot] Tarjimli - Terjemah Indonesia Arab2017-02-22T12:33:00+07:002017-02-22T12:33:00+07:00Ihfazhillahtag:blog.ihfazh.com,2017-02-22:/[telegram-bot]-tarjimli---terjemah-indonesia-arab.html<p class="first last"><strong>Tarjimli</strong> <em>bot</em> merupakan utilitas telegram yang dapat digunakan untuk <em>translate</em> indonesia ke arab.</p>
<div class="section" id="pendahuluan">
<h2>Pendahuluan</h2>
<p><strong>Bismillah</strong>,</p>
<p><tt class="docutils literal">Telegram</tt> merupakan salah satu platfrom chat yang cukup banyak digemari oleh orang orang selain <tt class="docutils literal">whatsapp</tt>. Terlebih dengan disediakannya fasilitas <tt class="docutils literal">API</tt> yang dapat digunakan untuk membuat bot, gratis pula. Juga berbagai fitur yang di tawarkan, sehingga bot terlihat lebih cantik dan mudah digunakan.</p>
<p>Sedangkan <strong>Tarjimli</strong> <em>bot</em>, memanfaatkan layanan telegram ini, yang berfungsi untuk menterjemahkan indonesia arab. Dengan tampilan yang mudah difahami, saya berharap semoga bot ini dapat bermanfaat untuk banyak orang.</p>
<blockquote>
<p><strong>Catatan</strong></p>
<p>Untuk sementara, bot ini hanya bisa terjemah <strong>Indonesia - Arab</strong>, adapun terjemahan <strong>Arab Indonesia</strong> belum dapat saya implementasikan. Tunggu versi selanjutnya yah..</p>
</blockquote>
</div>
<div class="section" id="tarjimli-bot">
<h2><tt class="docutils literal">@tarjimli_bot</tt></h2>
<blockquote>
<p>Anda juga dapat menonton langkah lewat video</p>
<iframe width="420" height="315"
src="https://www.youtube.com/embed/qyESiFkeODA">
</iframe></blockquote>
<p>Untuk bisa mengunakan bot ini, anda diharuskan untuk menginstall telegram di device anda. Kemudian cari akun dengan nama <tt class="docutils literal">tarjimli_bot</tt>. Kemudian pencet tombol start dibawah.</p>
<p>Andapun dapat meng-<em>click</em> link ini: <a class="reference external" href="https://telegram.me/tarjimli_bot">https://telegram.me/tarjimli_bot</a></p>
<img alt="" src="https://blog.ihfazh.com/images/cari_tarjimli.png" />
<img alt="" src="https://blog.ihfazh.com/images/start_tarjimli.png" />
<p>Setelah anda menekan tombol <tt class="docutils literal">start</tt> anda akan mendapatkan balasan dari bot, dan ada beberapa tombol dibawah. Fokus dengan <strong>layanan</strong>:</p>
<blockquote>
<ol class="arabic simple">
<li>Arab - Indonesia : <strong>Belum aktif</strong></li>
<li>Indonesia - Arab : <strong>Aktif</strong></li>
<li>Nama - Pegon : <strong>Aktif</strong></li>
<li>Angka - Arab : <strong>Aktif</strong></li>
</ol>
</blockquote>
<img alt="" src="https://blog.ihfazh.com/images/after_start_tarjimli.png" />
<p>Saya kira, tombol tombol di atas sudah dapat mewakili maksudnya yah.</p>
<p>Jadi, misal anda akan mencari arti kata <tt class="docutils literal">keyboard</tt>, maka cukup anda menekan tombol <tt class="docutils literal">Indonesia - Arab</tt>. Tunggu sebentar sampai ada balasan dari bot, kemudian masukkan kata yang akan anda cari. Kemudian klik kirim.</p>
<img alt="" src="https://blog.ihfazh.com/images/indo_arab_tarjimli.png" />
<img alt="" src="https://blog.ihfazh.com/images/hasil_indo_arab_tarjimli.png" />
<p>Namun, ternyata apabila anda akan membatalkan pencarian, cukup ketikkan <tt class="docutils literal">/cancel</tt> dan kemudian klik kirim. Maka pencarian akan dibatalkan.</p>
<p>Sekian, semoga bermanfaat dan dapat difahami dengan baik. Kalau belum, andapun dapat menghubungi saya di <a class="reference external" href="https://telegram.me/ibnamin">https://telegram.me/ibnamin</a>.</p>
</div>
[Tips] Git Anggap Tak Berubah2016-10-21T23:02:00+07:002016-10-21T23:02:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-10-21:/[tips]-git-anggap-tak-berubah.html<p>dengan tips ini, anda dapat menulis kode yang butuh credentials tanpa harus membaginya ke publik</p><p>Misalkan anda ingin menulis kode dan menyimpannya di <a href="" title="https://github.com">github</a>. Namun, di kode anda terdapat credentials, yang anda perlukan untuk <strong>testing</strong>. Jangan sampai anda ikut bagikan <strong>kode rahasia</strong> anda ini.</p>
<p>Ada beberapa langkah untuk mengantisipasinya:</p>
<ul>
<li>Buat file terpisah untuk credentials.py, isi dengan dummy credential. misal </li>
</ul>
<div class="highlight"><pre><span></span><code><span class="n">username</span> <span class="o">=</span> <span class="s1">'fakeusername'</span>
<span class="n">password</span> <span class="o">=</span> <span class="s1">'fakepassword'</span>
</code></pre></div>
<ul>
<li>Add and Commit </li>
<li>Ketikkan perintah <code>git update-index --assume-unchanged credentials.py</code></li>
</ul>
<p>Setelah ini, isi <code>username</code> dan <code>password</code> dengan yang asli. Check <code>git status</code>, apakah ada perubahan? Kalau tidak ada, maka langkah anda berhasil. Selamat.</p>Wifi Pada Acer one 14 ubuntu2016-07-03T19:02:00+07:002017-05-07T21:11:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-07-03:/wifi-pada-acer-one-14-ubuntu.html<p>Mengaktifkan wifi pada acer one 14 di ubuntu</p><h1>Bismillah,</h1>
<p>Ada sedikit problem ketika menginstall ubuntu (sekarang saya sedang menggunakan ubuntu 16.04) di acer one 14. Meskipun di windows (dari tokonya), wifi berjelan dengan semestinya.</p>
<p>Inti dari permasalahannya adalah, dikarenakan driver tidak terdeteksi dengan baik. Untuk mengatasinya, maka perlu kita menginstall driver tersebut.</p>
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>git<span class="w"> </span>build-essential
git<span class="w"> </span>clone<span class="w"> </span>https://github.com/lwfinger/rtl8723bu
<span class="nb">cd</span><span class="w"> </span>rtl8723bu
make
sudo<span class="w"> </span>make<span class="w"> </span>install
sudo<span class="w"> </span>modprobe<span class="w"> </span>-v<span class="w"> </span>8723bu
</code></pre></div>
<p>Nah, silahkan reboot, dan anda bisa mengaktifkan atau menonaktifkan menggunakan tombol fn-f4 berbarengan dengan bluetoth juga.</p>
<p><a href="https://forums.linuxmint.com/viewtopic.php?t=208434">Sumber</a></p>
<h2>Update 7/5/2017</h2>
<p>Ubuntu 17.04 dengan kernel 4.10 wifi sudah terdeteksi. Namun kabar buruknya, untuk meng-koneksikan ke router masih susah. Tidak terkoneksi. </p>
<p>Permasalahannya berada pada module <code>rtl8xxxu</code> dalam kernel ini yang belum berfungsi dengan baik.</p>
<p>Jadi, solusi sementara adalah mendisable dan blacklist module kernel tersebut.</p>
<h3>Blacklist</h3>
<p>Pergi, dan edit file <code>/etc/modprobe.d/blacklist.conf</code> dan tambahkan <code>blacklist rtl8xxxu</code> di akhir file. Save.</p>
<h3>Disable</h3>
<p>Jalankan perintah: <code>sudo modprobe -rv rtl8xxxu</code></p>
<p>Setelah itu lakukan perintah seperti di awal artikel ini.</p>
<p>Sumber: https://ubuntuforums.org/showthread.php?t=2359516&page=2</p>
<h3>Permasalahan lain Muncul 2 Device</h3>
<p>Dengan perintah diatas, maka akan menampilkan 2 device wifi. Kalau tidak mau, maka anda bisa menjalankan langkah berikut sebelum melakukan <code>make</code></p>
<ol>
<li>Buka file <code>MakeFile</code></li>
<li>Cari <code>EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE</code>, comment line tersebut</li>
<li>Baru setelah ini, <code>make</code></li>
<li><code>sudo make install</code></li>
<li><code>sudo modprobe -v 8723bu</code></li>
</ol>TarjimLi bot Telegram Bot Terjemah Indo Arab Arab Indo2016-06-29T20:11:00+07:002016-06-29T20:11:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-06-29:/tarjimli-bot-telegram-bot-terjemah-indo-arab-arab-indo.html<p class="first last">Bot untuk terjemah indo arab dan sebaliknya (versi yang akan datang)</p>
<p>Bismillah,
<strong>TarjimLi</strong> bot adalah telegram bot yang memberikan layanan berupa terjemah indonesia arab dan juga sebaliknya (akan ada pada versi berikutnya). Bot ini beralamat di <a class="reference external" href="http://telegram.me/tarjimli_bot">@tarjimli_bot</a>.</p>
<p>Adapun terjemah indonesia arab, maka saya menggunakan modul yang telah saya buat sebelumnya yaitu <a class="reference external" href="https://github.com/ihfazhillah/qaamus-python">qaamus-python</a> (atau <a class="reference external" href="{static}26-6-2016-[project]-qaamus-python-tool-untuk-terjemah-indo-arab.md">disini</a> untuk review dari blog ini) dengan mengubah controllernya (ini akan menjadi perubahan juga untuk <tt class="docutils literal"><span class="pre">qaamus-python</span></tt> nya.</p>
<div class="section" id="daftar-perintah">
<h2>Daftar Perintah</h2>
<blockquote>
Didalam telegram bot, yang namanya <em>command</em> atau perintah, itu adalah kata yang di awali dengan <em>garing</em> <cite>/</cite>.</blockquote>
<p>Untuk saat ini, daftar perintah yang ada adalah sebagai berikut:</p>
<ol class="arabic simple">
<li><cite>/start</cite> Untuk menampilkan pesan intro. Ini biasanya ada tombol bertuliskan start dibawah ketika anda baru masuk ke bot.</li>
<li><cite>/help</cite> Untuk menampilkan daftar perintah .</li>
<li><dl class="first docutils">
<dt><cite>/idar</cite> Untuk terjemahan indonesia arab. Setelah perintah ini harus ada query. Bila tidak ada, maka bot tidak akan memberikan balasan.</dt>
<dd>misal: <cite>/idar mobil pickup</cite></dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><cite>/angka</cite> Untuk terjemahan angka. Setelah perintah ini harus ada query. Dan bila tidak diberikan, maka tidak akan ada balasan.</dt>
<dd>misal: <cite>/angka 1234</cite></dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><cite>/pegon</cite> Untuk meng-<em>arab</em>-kan tulisan latin. Setelah perintah ini harus juga ada query. Kalau tidak ada, maka tidak akan memberikan balasan.</dt>
<dd>misal: <cite>/pegon surabaya</cite></dd>
</dl>
</li>
</ol>
</div>
<div class="section" id="daftar-layanan">
<h2>Daftar Layanan</h2>
<p>Dari daftar perintah diatas, kita bisa tahu -untuk saat ini- layanan yang tersedia di dalam tarjimli bot hanya ada 3:</p>
<ol class="arabic simple">
<li>Terjemah Indonesia Arab</li>
<li>Terjemah angka numerik, misal 123</li>
<li>Mengarabkan tulisan latin</li>
</ol>
</div>
<div class="section" id="kenapa-menggunakan-telegram">
<h2>Kenapa Menggunakan Telegram ?</h2>
<p>Di tahun kemarin, saya sempat membuat bot serupa, namun menggunakan whatsapp. Akan tetapi, karena dari whatsapp sendiri tidak mengijinkan penggunaan bot, dan mereka serius akan hal ini, banyak terjadi nomor yang ter-block. Daan, setelah berjalan hampir 6 bulan, nomor bot ini ter-block oleh whatsapp.
Kalau masih ingat, beberapa layanan yang ada kemarin adalah:</p>
<ol class="arabic simple">
<li>terjemah arab indo dan sebaliknya</li>
<li>hadith, pengecekan keabsahan hadith lewat <a class="reference external" href="http://dorar.net">dorar.net</a></li>
<li>cek ongkir <strong>jne</strong>, <strong>tiki</strong>, dan <strong>pos</strong> menggunakan API gratis dari RajaOngkir.</li>
</ol>
<p>Inilah, diantara alasan saya menggunakan telegram untuk pembuatan bot.</p>
</div>
<div class="section" id="dimana-bot-ini-hidup">
<h2>Dimana Bot ini Hidup?</h2>
<p>Sampai saat ini, bot ini hidup di Samsung Galaxy S3 saya dikarenakan keterbatasan dana. Rencananya, saya ingin menyewa vps untuk beberapa bot yang akan saya buat nanti InsyaAlloh. Dan anda bisa ikut support untuk ini.</p>
</div>
<div class="section" id="support">
<h2>Support</h2>
<p>Bila anda merasa mendapatkan manfaat dengan bot ini, anda bisa me-rate bot ini di <a class="reference external" href="tg://resolve?domain=storebot&start=tarjimli_bot">@storebot</a> dan memberikan komentar disana.
Anda juga bisa ikut me-like <a class="reference external" href="https://www.facebook.com/madingbengkelku">mading bengkelku fanspage</a> dan mendapatkan berita terbaru tentang bot ini, dan juga hal hal lain yang berkaitan dengan program/modul/bot yang saya buat.
Di fanspage tsb, anda juga memberikan saran dan kritik tentang bot ini.
Dan jangan lupa, ikut men-share bot ini dengan harapan banyak orang juga dapat merasakan manfaatnya.</p>
</div>
<div class="section" id="beberapa-tangkapan-layar">
<h2>Beberapa Tangkapan Layar</h2>
<div class="figure align-center">
<img alt="start command" src="https://blog.ihfazh.com/images/start.png" style="width: 250.0px; height: 400.0px;" />
</div>
<p>Perintah Start</p>
<div class="figure align-center">
<img alt="start command" src="https://blog.ihfazh.com/images/server_sedang_jalan.png" style="width: 250.0px; height: 400.0px;" />
</div>
<p>server sedang jalan</p>
<div class="figure align-center">
<img alt="start command" src="https://blog.ihfazh.com/images/pegon_selendangsutra.png" style="width: 250.0px; height: 400.0px;" />
</div>
<p>Perintah pegon</p>
<div class="figure align-center">
<img alt="start command" src="https://blog.ihfazh.com/images/angka.png" style="width: 250.0px; height: 400.0px;" />
</div>
<p>Perintah angka</p>
<div class="figure align-center">
<img alt="start command" src="https://blog.ihfazh.com/images/idar_gratis.png" style="width: 250.0px; height: 400.0px;" />
</div>
<p>Perintah idar</p>
</div>
[Project] Qaamus-python Tool untuk Terjemah Indo Arab2016-06-26T10:22:00+07:002016-06-26T10:22:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-06-26:/[project]-qaamus-python-tool-untuk-terjemah-indo-arab.html<p>Tool / Modul sederhana untuk terjemah indonesia arab.</p><p>Bismillah,</p>
<p><a href="http://qaamus.com">qaamus</a> adalah website yang memberikan layanan penterjemahan dari indonesia ke
arab. Saat ini, <a href="http://qaamus.com">qaamus</a> memiliki beberapa layanan:</p>
<ul>
<li>terjemah indonesia arab : dengan gabungan antara bing translator dengan <em>ketikan</em> ulang kamus munawwir, memberikan hasil yang <em>hampir</em> mendekati hasil yang pas.</li>
<li>pegon : layanan ini, mengubah kata kata kedalam tulisan arab. Tanpa menterjemahkannya</li>
<li>angka : adapun layanan ini, dia memberikan terjemahan angka dengan query angka yang anda berikan</li>
</ul>
<p>disitu, juga ada tab yang berisi kata kata bijak. Ter-list-kan disitu, dan andapun dapat <em>mengontak</em> admin untuk memberikan saran kata kata bijak yang ingin anda masukkan.</p>
<h2>qaamus-python</h2>
<p>Adapun <code>qaamus-python</code>, maka ini adalah script untuk query ke website diatas. Memiliki ke-3 layanan dasar diatas.
Saat ini, per-rilis 2.0.1 script ini sudah di<em>test</em> di python 2.7 dan 3.5 di linux ubuntu versi .... (lupa saya, bukan penghafal seri).</p>
<h3>Beberapa yang mungkin membuat anda tertarik:</h3>
<ul>
<li>Kemudahan syntax</li>
<li>cli-tool</li>
<li>template dapat dimodifikasi (untuk rilis mendatang bisa lebih mudah, tanpa mengubah controller)</li>
<li>gampang dimodifikasi (opensource, anda dapat melihat, membaca, menuliskan ulang source code), dengna lisensi MIT</li>
<li>tested di python versi 2.7 dan 3.5 </li>
</ul>
<h3>Installasi</h3>
<p>Ada beberapa cara untuk menginstall modul ini:</p>
<ol>
<li>
<p>installasi dari pypi
cukup mudah, karena hanya dengan mengetikkan
<code>pip install qaamus</code>
atau kalau anda ingin meng-upgrade
<code>pip install -U qaamus</code></p>
</li>
<li>
<p>installasi dari github (masih menggunakan pip installer)
<code>pip install git+https://github.com/ihfazhillah/qaamus-python</code></p>
</li>
<li>
<p>installasi dari github (dengan meng-clone or download zip)</p>
</li>
</ol>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/ihfazhillah/qaamus-python
<span class="nb">cd</span><span class="w"> </span>qaamus-python
python<span class="w"> </span>setup.py<span class="w"> </span>install
</code></pre></div>
<h3>ScreenShot</h3>
<p><img alt="Tangkapan Layar qaamus" src="https://raw.githubusercontent.com/ihfazhillah/qaamus-python/master/screenshot/qaamus1.gif"></p>[Tips] Mengetahui Dukungan Modul untuk Python32016-06-25T14:32:00+07:002016-06-25T14:32:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-06-25:/[tips]-mengetahui-dukungan-modul-untuk-python3.html<p>Website yang memberikan list daftar dukungan untuk python3</p><p><img alt="Tangkapan Layar py3wos" src="https://blog.ihfazh.com/images/python3_superpower.png">
Terkadang, kita merasa bingung, sudahkah modul yang akan kita pakai ada dukungan untuk python3 atau belum. Kalau satu dua sih, kita bisa saja buka halaman resmi modul tersebut. Tapi kalau banyak? Misalkan anda punya 15 list modul yang akan anda pakai untuk sebuah program yang akan anda tulis. Pastinya, membuka satu satu, belum lagi kalau lupa halaman resminya, harus <em>googling</em> dahulu adalah sesuatu yang membosankan.</p>
<p>Nah, dari itu, disana ada yang membuatkan list banyak modul, mana yang support mana yang belum. <a href="http://python3wos.appspot.com/">Python 3 Wall Of SuperPower</a> ditulis oleh <a href="http://uberpython.wordpress.com/">yuf</a> yang hampir setiap hari update (lihat time stamp di paling atas).</p>
<p>Di website tersebut ada dua warna. <strong>Hijau</strong> menandakan bahwa modul itu sudah support untuk python3. Sedangkan <strong>merah</strong> belum.</p>
<p><em>Nggak</em> menunggu modul yang akan ada pakai support untuk python3? Mulailah <a href="http://wiki.python.org/moin/PortingToPy3k/"><em>ngeport</em> code untuk python3</a></p>Intro2016-06-25T13:40:00+07:002016-06-25T13:40:00+07:00Ihfazhillahtag:blog.ihfazh.com,2016-06-25:/intro.html<p>Seperti Muqoddimah, intro saja</p><p>Bismillah,</p>
<p>Ini adalah page pertama saya, dan blog pertama saya (setelah sekian lama tidak <em>ngeblog</em>).</p>
<p>Blog ini, saya bangun menggunakan <strong>Pelican</strong>, static site generator menggunakan python. Bisa menerima inputan file berupa <em>markdown</em> atau <em>restructuredText</em>, atau bahkan bisa menggunakan <em>ipynb</em>. Sedangkan python sendiri adalah bahasa pemrograman yang terkenal mudah syntaxnya. Anda bisa baca baca di <a href="http://python.org">website resminya</a>.</p>
<p>Adapun blog ini, maka ada beberapa macam artikel yang akan saya tulis:</p>
<ul>
<li>
<p><strong>Tentang Islam</strong> : Untuk meneruskan ilmu yang sudah saya dapat, dan aku tulis, atau sekadar saling mengingatkan karena <em>agama adalah nasehat</em>.</p>
</li>
<li>
<p><strong>Tutorial</strong> : Tutorial ini apa saja, tidak terbatas hanya pada pemrograman saja</p>
</li>
<li>
<p><strong>Project</strong> : Nah, ini projek yang saya kerjakan, rilis, keterangan, dokumentasi</p>
</li>
</ul>
<p>Apa lagi ya? Mungkin ini dulu. Semoga tetap bisa bermanfaat.</p>