Sejak ramainya framework dari masing-masing bahasa pemrograman yang terus dikembangkan baik oleh komunitas maupun perusahaan tech seperti Oracle, Meta, Google dll,
hingga kini semakin banyak variasi masing-masing framework bahasa pemrograman yang mendukung pengembangan perangkat lunak.
Kesemuanya menawarkan kelebihan yang adjustable, tentunya bergantung dengan okupansi dari para pengembang yang memakai stack tersebut, sebut saja, Eloquent ORM yang dimiliki Laravel,
Hibernate yang digunakan Java, TypeORM dari Typscript/NodeJs, hingga Django ORM yang akan kita bahas kali ini.
Perbedaan ORM dengan Raw SQL Query
ORM adalah Object Relational Mapping yang membuat programmer berinteraksi dengan database menggunakan object dalam bahasa pemrograman yang dipakainya, alih-alih menulis SQL query
yang berinteraksi dengan engine database secara langsung.
Raw Sql Query adalah perintah sql secara konvensional, tidak seperti ORM yang dapat dijembatani dengan bahasa pemrograman yang diakomodir oleh ORM yang diusung oleh framework terkait.
Bagi pemula yang sedang mempelajari pemrograman, wajib hukumnya berkenalan dengan Query database, biasanya di tahap awal, programmer akan belajar Raw SQL Query, contoh :
SELECT * FROM pelanggan WHERE status = 'aktif';
di mana perintah di atas menampilkan data dari tabel pelanggan yang memiliki kolom bernilai aktif, atau sederhananya, menampilkan data pelanggan yang aktif.
Setelah memahami konsep dasar query raw sql, lambat laun programmer pemula tadi akan mencoba framework bahasa pemrograman yang memiliki metodenya, yang memiliki caranya sendiri,
dalam hal ini ORM karena tuntutan tugas agar lebih efisien.
Keuntungan ORM
ORM biasanya menyediakan mekanisme untuk menghindari SQL injection, karena ORM menangani parameterisasi query secara otomatis.
Raw SQL, programmer harus sangat berhati-hati dengan query SQL untuk memastikan code yang ditulis menjadi aman seperti prepared statements untuk menghindari SQL injection.
ORM memakai objek dan metode yang lebih mudah dipamahi untuk berinteraksi dengan database, sehingga programmer tidak perlu menulis query SQL secara langsung. Ini membuat kode lebih clean dan mudah dipahami.
Raw SQL malah harus buat programmer buat menulis query SQL secara manual untuk setiap operasi database. Yang seperti ini memang buat programmer punya kontrol lebih terhadap operasi database,
tapi malah akan jadi boilerplate atau code yang akan ditulis ulang, padahal cara kerja codingnya sama saja, contoh jika di php native yang tanpa orm kita jalankan sql raw query
Raw SQL malah harus buat programmer buat menulis query SQL secara manual untuk setiap operasi database
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "INSERT INTO pelanggan (nama, email) VALUES ('Agus', '[email protected]')";
if ($conn->query($sql) === TRUE) {
echo "Data terinput";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
Namun jika menggunakan ORM Eloquent di Laravel, maka akan menjadi lebih ringkas
$pelanggan = new Pelanggan();
$pelanggan->nama = 'Agus';
$pelanggan->email = '[email protected]';
$pelanggan->save();
Sama halnya di Django ORM
from app_saya.models import Pelanggan
pelanggan = Pelanggan(nama='Agus', email='[email protected]')
pelanggan.save()
Terlihat lebih mudah bukan ?
Belajar Query Database dengan Django ORM
Sesuai judul tertulis, fokus kita kali ini akan mempelajari cara melakukan querying, yang akan mengoperasikan database di environment Django.
Catatan, penulis beranggapan bahwa pembaca telah menginstall Django di localhost, dan mengisi models.py di salah satu app nya dengan models berikut
https://github.com/Creativauz/tutorial/blob/master/models.py
Lalu jalankan mode interactive shell, dengan : python manage.py shell, kemudian impor dengan cara
from nama_app.models import *
1. Ambil semua data
Di mana nama_app adalah app yang kamu buat dan modelsnya telah kamu isi dari models dari github repo Creativauz.
Setelah itu ketikkan,
>>> from adminmarketing.models import *
>>> data = DataMarketing.objects.all()
>>> for x in data:
... print(x.nama_marketing, x.email_marketing)
...
marketing1
Penjelasan : Sintaksnya adalah NamaTable.objects.perintah()
Pada contoh di atas, adalah DataMarketing sebagai tabel, lalu objects.all() yang kegunaannya mengambil semua isi database
jika di raw sql query, sama seperti
SELECT * FROM DataMarketing;
lalu menggunakan perulangan for untuk menampilkan semua data, dan hanya kolom nama_marketing dan email_marketing saja yang tampilkan berulang, terlihat
nilai yang ditampilkan adalah marketing1
2. Filter berdasar kondisi
Contoh hanya menampilkan id dari tabel DataPelanggan yang memiliki nilai kolom status_pembayaran bernilai Paid
Dengan catatan bahwa sistem telah menginput data seseorang dan memberi kolom status_pembayaran bernilai Paid
>>> from adminmarketing.models import *
>>> pelanggan = DataPelanggan.objects.filter(status_pembayaran='Paid')
>>> for x in pelanggan:
... print(x.nama_pelanggan, x.status_pembayaran)
...
Dewa Budjana Paid
Contoh di atas, adalah data nama_pelanggan bernilai Dewa Budjana yang memiliki status_pembayaran Paid
3. Mengambil satu data dengan get()
Khusus get() hanya gunakan jika mencari 1 nilai saja di sebuah kolom, biasanya untuk melakukan pengecekan atau debugging
apakah data ini emang ada atau tidak terinput, jika tidak ada data atau lebih dari satu data, akan ada error Exception, contoh :
>>> cust = DataPelanggan.objects.get(email='[email protected]')
>>> print(cust)
Andra Ramadhan
4. Order data dengan order_by
Mengambil semua data pelanggan dengan cara mengurutkan berdasar nilai dari sebuah kolom yang dapat diurutkan
dalam hal ini nilai yang memiliki integer, yaitu kolom -> harga = models.PositiveIntegerField()
Berikut cara pengurutan Ascending, yaitu dari terkecil ke terbesar
>>> pelanggan = DataPelanggan.objects.all().order_by('harga')
>>> print(pelanggan)
<QuerySet [<DataPelanggan: Andra Ramadhan>, <DataPelanggan: Duta>, <DataPelanggan: Dewa Budjana>]>
Sebaliknya, cara di bawah ini adalah pengurutan Descending, dari terbesar ke terkecil
>>> pelanggan_desc = DataPelanggan.objects.all().order_by('-harga')
>>> print(pelanggan_desc)
<QuerySet [<DataPelanggan: Dewa Budjana>, <DataPelanggan: Duta>, <DataPelanggan: Andra Ramadhan>]>
5. Querying berdasar limitasi (first(), last() exists() )
# Ambil pelanggan pertama berdasarkan urutan default
first_pelanggan = DataPelanggan.objects.first()
# Ambil pelanggan terakhir atau yang terbaru
last_pelanggan = DataPelanggan.objects.last()
# Periksa apakah ada pelanggan dengan harga lebih dari 1 juta yang akan mengembalikan nilai True or False
exists = DataPelanggan.objects.filter(harga__gt=1000000).exists()
print("Ada pelanggan:", exists)
6. F Expression
F expression dalam Django ORM yang memungkinkan kita untuk melakukan operasi langsung pada field database tanpa harus mengambil data tersebut terlebih dahulu ke dalam Python.
Dengan kata lain, F memungkinkan kita untuk membandingkan atau melakukan operasi aritmatika/logika langsung antar field database,
tanpa perlu mengakses nilainya sebagai Python object.
Misalnya, kita ingin mengurangi field harga dengan nilai dari field diskon di model DataPelanggan.
>>> from django.db.models import F
>>> DataPelanggan.objects.filter(diskon__isnull=False).update(harga=F('harga') - F('diskon'))
3
7. Q Expressions (Query Kompleks dengan OR atau AND)
Tujuan: Menggabungkan kondisi query dengan OR atau AND.
from django.db.models import Q
pelanggan = DataPelanggan.objects.filter(
Q(status_pembayaran='Paid') | Q(jumlah_termin__gt=2)
)
Penjelasan:
Q: Digunakan untuk kondisi kompleks.
|: Kondisi OR.
&: Kondisi AND.
jumlah_termin__gt=2
Field: jumlah_termin merujuk ke kolom dalam model DataPelanggan yang menyimpan jumlah termin pembayaran seorang pelanggan.
Operator: gt adalah singkatan dari "greater than" atau "lebih besar dari".
Angka 2: Menunjukkan nilai pembanding.
Jadi, query ini berarti "Cari pelanggan dengan jumlah termin pembayaran lebih dari 2."
8. Select Related
select_related (Mengurangi Query untuk Relasi OneToMany)
Tujuan:
Menggunakan JOIN SQL untuk mengambil data terkait dalam satu query.
Cocok untuk relasi ForeignKey
Contoh Model:
class PaketPelanggan(models.Model):
nama_paket = models.CharField(max_length=200)
class DataPelanggan(models.Model):
nama_pelanggan = models.CharField(max_length=200)
paket_yang_dipesan = models.ForeignKey(PaketPelanggan, on_delete=models.CASCADE)
Berikut ini jika tanpa select_related atau dengan cara banyak query
pelanggan = DataPelanggan.objects.all()
for p in pelanggan:
print(p.nama_pelanggan, p.paket_yang_dipesan.nama_paket)
Sedangkan berikut ini, jika memakai select_related, dalam sekali query saja
pelanggan = DataPelanggan.objects.select_related('paket_yang_dipesan').all()
for p in pelanggan:
print(p.nama_pelanggan, p.paket_yang_dipesan.nama_paket)
Tanpa select_related, Django membuat query terpisah setiap kali Anda mengakses paket_yang_dipesan.
Dengan select_related, Django membuat satu query SQL menggunakan JOIN, sehingga lebih efisien.
9. prefetch_related (Mengurangi Query untuk Relasi ManyToMany)
Kegunaanyna adalah :
Mengambil data dari tabel terkait dalam query terpisah, lalu menggabungkannya di Python.
Cocok untuk relasi ManyToMany atau Reverse ForeignKey (banyak-ke-banyak).
Contoh Model:
class Pembayaran(models.Model):
pelanggan = models.ForeignKey(DataPelanggan, on_delete=models.CASCADE, related_name="pembayaran")
jumlah = models.PositiveIntegerField()
batch = models.PositiveIntegerField()
Berikut ini jika tanpa prefetch_related yang mana akan banyak query dijalankan
pelanggan = DataPelanggan.objects.all()
for p in pelanggan:
for pembayaran in p.pembayaran.all():
print(p.nama_pelanggan, pembayaran.jumlah)
Berikut ini jika dengan prefetch_related yang artinya menggabungkan 2 query terpisah
pelanggan = DataPelanggan.objects.prefetch_related('pembayaran').all()
for p in pelanggan:
print(p.nama_pelanggan)
for pembayaran in p.pembayaran.all():
print(" Batch:", pembayaran.batch, "Jumlah:", pembayaran.jumlah)
Tanpa prefetch_related, setiap iterasi akan memicu query baru.
Dengan prefetch_related, Django mengambil semua data pembayaran dalam satu query tambahan.
10. nnotate (Menambah Kolom Dinamis)
Kegunaannya adalah untuk Menambah kolom dinamis berdasarkan perhitungan tertentu (misalnya COUNT, SUM).
Contoh untuk menghitung jumlah pembayaran untuk setiap pelanggan
from django.db.models import Count
pelanggan = DataPelanggan.objects.annotate(total_pembayaran=Count('pembayaran'))
for p in pelanggan:
print(p.nama_pelanggan, "Total Pembayaran:", p.total_pembayaran)
Count('pembayaran'): Menghitung jumlah pembayaran yang terkait dengan setiap pelanggan.
Hasilnya adalah kolom tambahan total_pembayaran yang bisa digunakan seperti field biasa.
11. Aggregate (Perhitungan Tingkat Tabel)
Memiliki beberapa fungsi untuk operasi, jenis Aggregate, yaitu melakukan perhitungan pada seluruh tabel, seperti SUM, AVG, MIN, MAX.
Untuk menghitung total semua pembayaran dari pelanggan
from django.db.models import Sum
total_pembayaran = Pembayaran.objects.aggregate(total=Sum('jumlah'))
print("Total Pembayaran:", total_pembayaran['total'])
Untuk mencari rata-rata pembayaran pelanggan
from django.db.models import Avg
>>> average_pembayaran = Pembayaran.objects.aggregate(average=Avg('jumlah'))
>>> print("Rata-rata Pembayaran:", average_pembayaran['average'])
Rata-rata Pembayaran: 3231997.5
Untuk mencari pelanggan yang melakukan pembayaran dengan nominal terkecil
>>> from django.db.models import Min
>>> min_pembayaran = Pembayaran.objects.aggregate(minimum=Min('jumlah'))
>>> print("Pembayaran Terkecil:", min_pembayaran['minimum'])
Pembayaran Terkecil: 1343990
Untuk mencari pelanggan yang melakukan pembayaran dengan nominal terbesar
>> from django.db.models import Max
>>> max_pembayaran = Pembayaran.objects.aggregate(maximum=Max('jumlah'))
>>> print("Pembayaran Terbesar:", max_pembayaran['maximum'])
Pembayaran Terbesar: 4736000
aggregate() mengembalikan dictionary dengan hasil perhitungan.
Hasil total adalah jumlah dari kolom jumlah untuk semua pembayaran.
12. Raw SQL
Jika menggunakan Django dirasa masih butuh pengenalan, karena terlalu terbiasa menggunakan Raw SQL, bisa pakai cara ini
from django.db import connection
query = "SELECT * FROM adminmarketing_datapelanggan WHERE harga > %s"
with connection.cursor() as cursor:
cursor.execute(query, [1000000])
rows = cursor.fetchall()
for row in rows:
print(row)
Gunakan connection.cursor() untuk mengeksekusi query SQL. Hasilnya adalah data raw (biasanya berbentuk tuple).
Beberapa materi di atas kami share untuk pembelajaran pemrograman web apps dengan Django Python, khususnya dalam hal operasi database, semoga bermanfaat.