Frontend untuk si Backend - Django Unicorn PART 2
Dalam tulisan sebelumnya sudah mencoba fungsi-fungsi dasar unicorn, dalam kali ini akan buat untuk CRUD. Pertama mari buat bagian list.
list-contact.py
Berikut isi komponen list-contact.py
from django.shortcuts import redirect
from django_unicorn.components import LocationUpdate, QuerySetType, UnicornView
from contact.models import ContactForm
class ListContactView(UnicornView):
data: QuerySetType[ContactForm] = ContactForm.objects.none()
search: str = ""
def mount(self):
"""On mount, populate the movies property w/ a QuerySet of all movies"""
self.load_data()
def load_data(self, query=None):
datas = ContactForm.objects.all()
if query:
datas = datas.filter(name__icontains=query)
datas = datas.order_by("-id")
self.datas = datas
def updated_search(self, query):
self.load_data(query)
def delete(self, id):
ContactForm.objects.filter(id=id).delete()
self.mount()
self.reset()
Mari bahas perblok
data: QuerySetType[ContactForm] = ContactForm.objects.none()
search: str = ""
Properti atau variable untuk menampung data:
- data: Menampung untuk querysety dari contactform
- search: Menampung keyword search yang akan ditrigger dari komponen
list-contact.html
def mount(self):
"""On mount, populate the movies property w/ a QuerySet of all movies"""
self.load_data()
def load_data(self, query=None):
data = ContactForm.objects.all()
if query:
data = data.filter(name__icontains=query)
data = datas.order_by("-id")
self.data = data
def updated_search(self, query):
self.load_data(query)
Fungsi mount()
adalah fungsi bawaan dari unicorn yang akan dijalankan ketika komponen ini di-load
Fungsi load_data()
adalah fungsi yang dibuat untuk mencari data dari model terkait, ini bukan fungsi bawaan, ini yang dibuat sendiri
Fungsi updated_search()
adalah fungsi bawaan yang akan mendeteksi perubahan pada variable search, ini formatnya updated_<nama_variable>()
def delete(self, id):
ContactForm.objects.filter(id=id).delete()
self.mount()
self.reset()
Sesuai namanya ini fungsi untuk menghapus data dari contactForm, sedangkan untuk self.mount()
untuk memastikan data ke-refresh, sedangkan reset untuk mengambalikan ke state awal.
Untuk tampilannya bbah komponen list-contact.html
menjadi seperti berikut:
<div>
<div class="float-right mb-4">
<a href="{% url 'add-form' %}" class="btn btn-success"> Add Form </a>
</div>
<!--Section: Contact component list-->
<div class="row ">
<div class="col-4">
<input unicorn:model="search" type="text" id="myInput" class="form-control" placeholder="Search for names..">
</div>
</div>
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{% for single in data %}
<tr>
<td>{{ single.name }}</td>
<td>{{ single.email }}</td>
<td>
<a class="btn btn-success" href="{% url 'edit-form' id=single.id %}">Update</a>
<button class="btn btn-danger"
onclick="swal.fire({
icon: 'warning',
title: 'Are you sure??',
text: 'data deleted permanently!!',
showCancelButton: true,
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
}).then((result) => {
if (result.isConfirmed) {
Unicorn.call('list-contact', 'delete', '{{ single.id}}')
}
})">
Delete</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
Mari bahas "perbaris"
Pertama
<div class="float-right mb-4">
<a href="{% url 'add-form' %}" class="btn btn-success"> Add Form </a>
</div>
Ini masih django template sederhana, itu sebuah link untuk menuju path add-form
alias untuk menambahkan kontak form
Pastikan url atau views tujuan sudah disiapkan, sengaja gak bahas itu karena itu tidak ada sangkut pautnya langsung dengan unicorn
<div class="col-4">
<input unicorn:model="search" type="text" id="myInput" class="form-control" placeholder="Search for names..">
</div>
kode di atas mirip dengan di tulisan sebelumnya, melakukan request langsung ke komponen list-contact.py
{% for single in data %}
<tr>
<td>{{ single.name }}</td>
<td>{{ single.email }}</td>
<td>
<a class="btn btn-success" href="{% url 'edit-form' id=single.id %}">Update</a>
<button class="btn btn-danger"
onclick="swal.fire({
icon: 'warning',
title: 'Are you sure??',
text: 'data deleted permanently!!',
showCancelButton: true,
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
}).then((result) => {
if (result.isConfirmed) {
Unicorn.call('list-contact', 'delete', '{{ single.id}}')
}
})">
Delete</button>
</td>
</tr>
{% endfor %}
Itu looping biasa, bedanya data
datang dari list-contact.py
dan pada bagian onclick
saya memanggil swal untuk modal confirm sedangkan Unicorn.call('list-contact', 'delete', '{{ single.id}}')
Ini fungsi dari unicorn yaitu bisa memanggil langsung method di list-contact.py
dari javascript.
Sedangkan untuk bagian href="{% url 'edit-form' id=single.id %}
ini fungsi url django standar, mengirimkan ke url path edit form dengan param id dari data yang dipilih.
Sehingga hasilnya seperti berikut
Form
Sama dengan sebelumnya perlu buat dulu komponen baru, saya beri nama form-contact
sehingga menghasilkan form-contact.py
dan form-contact.html
form-contact.py
from django import forms
from django.shortcuts import redirect
from django_unicorn.components import QuerySetType, UnicornView
from contact.models import ContactForm
class FormContact(forms.Form):
contact_id = forms.IntegerField(required=False)
name = forms.CharField(max_length=100, required=True)
email = forms.EmailField(max_length=100, required=True)
text = forms.Textarea()
def clean(self):
cleaned_data = super().clean()
email = cleaned_data.get("email")
pk = cleaned_data.get("contact_id")
if email:
exist = ContactForm.objects.filter(email=email).first()
if exist:
if exist.id != pk:
self.add_error("email", "email already used")
class FormContactView(UnicornView):
form_class = FormContact
name = ""
email = ""
text = ""
contact_id = None
def mount(self):
"""On mount, populate the movies property w/ a QuerySet of all movies"""
if self.contact_id:
self.populate(self.contact_id)
def populate(self, id):
detail = ContactForm.objects.get(id=id)
self.name = detail.name
self.email = detail.email
self.text = detail.text
self.contact_id = id
def submit(self):
collect = {"name": self.name, "email": self.email, "text": self.text}
if self.is_valid():
if self.contact_id:
contact = ContactForm.objects.get(id=self.contact_id)
contact.name = self.name
if contact.email != self.email:
contact.email = self.email
contact.text = self.text
else:
contact = ContactForm(**collect)
contact.save()
return redirect("list-contact")
Kembali bahas perblok
class FormContact(forms.Form):
contact_id = forms.IntegerField(required=False)
name = forms.CharField(max_length=100, required=True)
email = forms.EmailField(max_length=100, required=True)
text = forms.Textarea()
def clean(self):
cleaned_data = super().clean()
email = cleaned_data.get("email")
pk = cleaned_data.get("contact_id")
if email:
exist = ContactForm.objects.filter(email=email).first()
if exist:
if exist.id != pk:
self.add_error("email", "email already used")
Tidak ada yang aneh di bagian ini, ini hanyalah django forms pada umumnya, tidak spesifik django unicorn
form_class = FormContact
name = ""
email = ""
text = ""
contact_id = None
- form_class = Variable "bawaan" untuk identifikasi bahwa django unicorn akan mengunkana django form yang mana
- name = Variable yang akan menampung "name"
- email = Variable yang akan menampung "email"
- text = Variable ayng akan menampung "text"
- contact_id = Variable yang akan menampung id
def mount(self):
"""On mount, populate the movies property w/ a QuerySet of all movies"""
if self.contact_id:
self.populate(self.contact_id)
def populate(self, id):
detail = ContactForm.objects.get(id=id)
self.name = detail.name
self.email = detail.email
self.text = detail.text
self.contact_id = id
Sama seperti sebelumnya, mount()
, sedangkan populate()
untuk populas data jika id diberikan saat initialisasi komponent
def submit(self):
collect = {"name": self.name, "email": self.email, "text": self.text}
if self.is_valid():
if self.contact_id:
contact = ContactForm.objects.get(id=self.contact_id)
contact.name = self.name
if contact.email != self.email:
contact.email = self.email
contact.text = self.text
else:
contact = ContactForm(**collect)
contact.save()
return redirect("list-contact")
Fungsi submit()
standar gak ada yang aneh, untuk insert data jika tidak ada contact_id
dan update jika ada.
Lalu di form-contact.html
<div>
<!--Section: Contact v.2-->
<section class="mb-4">
<!--Section heading-->
<h2 class="h1-responsive font-weight-bold text-center my-4">Contact us</h2>
<div class="row">
<!--Grid column-->
<div class="col-md-12 mb-md-0 mb-5">
<!--Grid row-->
<div class="row">
<!--Grid column-->
<div class="col-md-6">
<div class="md-form mb-0">
<span class="error">{{ unicorn.errors.name.0.message }}</span>
<input unicorn:model="contact_id" type="hidden" id="id" name="id" class="form-control">
<input unicorn:model="name" type="text" id="name" name="name" class="form-control">
<label for="name" class="">Your name {{ name }}</label>
</div>
</div>
<!--Grid column-->
<!--Grid column-->
<div class="col-md-6">
<div class="md-form mb-0">
<span class="error">{{ unicorn.errors.email.0.message }}</span>
<input unicorn:model="email" type="email" id="email" name="email" class="form-control">
<label for="email" class="">Your email {{ email }} </label>
</div>
</div>
<!--Grid column-->
</div>
<!--Grid row-->
<!--Grid row-->
<div class="row">
<!--Grid column-->
<div class="col-md-12">
<div class="md-form">
<textarea unicorn:model="text" type="text" id="message" name="message" rows="2" class="form-control md-textarea"></textarea>
<label for="message">Your message</label>
</div>
</div>
</div>
<!--Grid row-->
<div class="text-center text-md-left">
<button class="btn btn-success" unicorn:click="submit">Submit</button>
<a class="btn btn-warning" href={% url 'list-contact'%}>Cancel</a>
</div>
<div class="status"></div>
</div>
<!--Grid column-->
</div>
</section>
</div>
Di sini cukup to the point, di mana setiap field di html di atas binding dengan setiap variable di form-contact.py
Yang sedikit beda cara panggilnya
{% unicorn 'form-contact' contact_id=id%}
Perintah di atas saat inisialisasi komponen akan sekalian mengirimkan nilai dari "contact_id".
Hasil akhirnya
Fungsi di atas langsung bekerja dengan baik kan termasuk validasi saat nulis email, itu dia akan langsung membaca ke django forms yang ditulis sebelumnya.
Dan ini hasil akhirnya
Sampai jumpa di tulisan lain lagi.