Frontend untuk si Backend - Django Unicorn PART 1

Dalam tulisan ini saya fokus di akhir tulisan bisa membuat "crud" menggunakan django unicorn, jadi saya tidak akan membahas bagaimana membuat struktur template di django, saya pernah menulisnya di sini dan di sini.

Tujuan di sini akan membuat kontak form yang akan menerapkan

  • inline validation
  • form validation tanpa reload
  • auto search di tabel

Pertama mari install dulu django unicorn (selanjutnya kita sebut saja unicorn), saya menggunakan pipenv, kalian bisa menggunakan tool favorit kalian masing-masing

pipenv install django-unicorn
install django unicorn

Mari lihat dulu struktur folder django saya

.
├── contact
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── core
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── manage.py
├── Pipfile
├── Pipfile.lock
└── templates
    └── layout.html

Penjelasan

  1. Saya memiliki sebuah project django dengan nama "core"
  2. Saya memiliki satu "app" dengan nama "contact"
  3. Saya membuat template untuk layout terpusat di folder "templates"

Konfigurasi

Karena tadi sudah memasang django unicorn sekarang saatnya kita mendaftarkan paket ini di django, ubah core/settings.py di bagian INSTALLED_APPS

INSTALLED_APPS = [
	...
    "contact",
    "django_unicorn",
]

Daftarkan pula urls untuk unicorn di core/urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("unicorn/", include("django_unicorn.urls")),
]

Lalu di bagian templates/layout.html pastikan kita sudah pasang script unicorn

{% load unicorn %}
<html>
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
   

  {% unicorn_scripts %}

  <style>
    [unicorn\:error\:invalid] {
      border: 1px solid red !important;
    }
    [unicorn\:error\:required] {
      border: 1px solid red !important;
    }
  </style>
  </head>
  <body>
    <main class="container">
      {% csrf_token %}
      {% block content %}
      {% endblock %}
    </main>

  </body>
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</html>

Penjelasan

  1. Baris pertama saya melakuan "load" untuk unicorn
  2. Menambahkan css untuk unicorn error
  3. Selanjutnya saya juga memastikan bahwa unicorn script sudah terpasang
  4. Pastikan csrf_token terpasang
  5. Membuat blok content untuk memastikan bagian tersebut dinamis sesuai page yang diakses
  6. Sisanya hanya cdn javascript dan css untuk kebutuhan dasar

Terminologi

Unicorn meyebut fiturnya dengan komponen, komponen ini terbagi ke dalam 2 bagian:

  1. komponen views
  2. komponen html

Komponen views ini mirip dengan views di django pada umumnya, berisi fungsi yang akan kita trigger, bedanya adalah fungsi di dalam komponen views itu bisa langsung dipanggil melalui komponen html tanpa perlu melakukan reload page, sederhananya komponen html saat memanggil fungsi komponen views secara otomatis melakukan ajax call, bedanya yang di-return tak hanya json tapi bisa dibilang satu komponen html.

Sebelum membuat komponen mari buat halaman untuk mencoba, karena kita akan buat kontak form dan list kontak yang terdaftar, mari buat halaman untuk dua hal tersebut, ini belum ada kaitannya dengan unicorn, ini masih django biasa

// contact/views.py
from django.shortcuts import render


def list_contact(request):
    return render(request, "list.html")


def form_contact(request, id=None):
    context = {"id": id}

    return render(request, "form.html", context)

// contact/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("list", views.list_contact, name="list-contact"),
    path("form/", views.form_contact, name="add-form"),
    path("form/<int:id>", views.form_contact, name="edit-form"),
]


//core/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("contact.urls")),
    path("unicorn/", include("django_unicorn.urls")),
]

lalu buat dua berkas di contact/templates/ yaitu list.html dan form.html

//contact/templates/form.html
{% extends "layout.html" %}
{% load unicorn %}
 {% block content %}
 <section class="mb-4">
	Komponen form akan di sini
 </section>
 {% endblock %}

//contact/templates/list.html
{% extends "layout.html" %}
{% load unicorn %}
 {% block content %}
 <section class="mb-4">
	Komponen list akan di sini
 </section>
 {% endblock %}

Komponen

Sebelum masuk crud, mari bermain-main dengan komponen dan action unicorn, mari buat list komponen terlebih dahulu dengan perintah

//format
{{ ./manage.py startunicorn nama-app nama-komponen }}

./manage.py startunicorn contact list-contact

Perintah di atas akan menghasilkan dua berkas

  1. contact/templates/list-contact.html
  2. contact/components/list_contact.py
contact/
├── admin.py
├── apps.py
├── components
│   ├── __init__.py
│   ├── list_contact.py
├── __init__.py
├── migrations
│   ├── 0001_initial.py
│   └── __init__.py
├── models.py
├── templates
│   ├── form.html
│   ├── list.html
│   └── unicorn
│       ├── list-contact.html
├── tests.py
├── urls.py
└── views.py

Mari buka list_contact.py isinya default seperti ini

from django_unicorn.components import UnicornView


class ListContactView(UnicornView):
    pass

Lalu tambahkan seperti ini

from django_unicorn.components import UnicornView


class ListContactView(UnicornView):
    name: str=""

Dan isi dari contact/templates/list-contact.html seperti berikut

<div>
   <input unicorn:model="name" type="text" class="form-control" />


   <h2 class="h1-responsive font-weight-bold text-center my-4">{{ name | upper }}</h2>
</div>
Penting: dalam komponen html pastikan hanya ada satu container yang membungkus

Lalu di html list view biasa kita panggil komponen list-contact

{% extends "layout.html" %}
{% load unicorn %}
 {% block content %}
 <section class="mb-4">

   <!--Section heading-->
   <h2 class="h1-responsive font-weight-bold text-center my-4">Contact us</h2>
 	{% unicorn 'list-contact'%}
 </section>
 {% endblock %}

Hasilnya

Penjelasan

Pada bagian komponen html di input, di sana ada atribut kustom bernama unicorn:model="name" bagian ini lah yang membuat inputan ini terkoneksi secara langsung ke properti name di dalam class ListContactView, karena kita tidak mendefinisikan trigger-nya secara otomatis untuk di input ini akan langsung dieksekusi saat ada ketikan, jika dibandingkan dengan javascript ini mirip dengan onkeyup

Action

Selain binding langsung dengan properti, komponen html bisa langsung berinteraksi dengan fungsi di dalam class, tambahkan fugsi di dalam class

from django.utils import timezone
from django_unicorn.components import UnicornView


class ListContactView(UnicornView):
    name: str=""

    def get_time(self):
        current = timezone.now()
        self.name = current.strftime("%H:%M:%S")

Di dalam komponen html, tambahkan tombol untuk memanggil fungsi yang sudah dibuat

<div>
   <input unicorn:model="name" type="text" class="form-control" />


   <h2 class="h1-responsive font-weight-bold text-center my-4">{{ name | upper }}</h2>
   
   <button unicorn:click="get_time" class="btn btn-info">Today</button>
</div>

Hasilnya

Penjelasan

Dalam view saya membuat fungsi get_time dan di komponen html di dalam button saya menambahkan trigger unicorn:click=get_time, jika dibandingkan dengan javascript ini mirip dengan onclick

Fungsi dengan parameter

Mari ubah dulu fungsi agar bisa menampung parameter

from datetime import timedelta

from django.utils import timezone
from django_unicorn.components import UnicornView


class ListContactView(UnicornView):
    name: str = ""

    def get_time(self, hour=None):
        current = timezone.now()
        if hour:
            current = current + timedelta(hours=hour)
        self.name = current.strftime("%H:%M")

Dan komponen html

<div>
    <h1> Sekarang jam {% now "H:i" %} </h1>
   <input unicorn:model="name" type="text" class="form-control" />


   <h2 class="h1-responsive font-weight-bold text-center my-4">{{ name | upper }}</h2>
   
   <button unicorn:click="get_time" class="btn btn-info">Today</button>
   <button unicorn:click="get_time(2)" class="btn btn-info">Add 2 hour</button>
   <button unicorn:click="get_time(3)" class="btn btn-info">Add 3 hour</button>
   <button unicorn:click="get_time(4)" class="btn btn-info">Add 4 hour</button>
</div>

Hasilnya

Oke, di part 1 ini selesai dulu sebagai perkenalan dengan unicorn, di tulisan selanjutnya baru kita membuat crud.