Catatan belajar django part 2: Django ORM
Pada tulisan sebelumnya cukup sering membahas model dan database, tapi bagaimana sebenarnya django bermain dengan database? Di tulisan ini akan sedikit membahas itu, makanya tulisan kali ini berfokus kepada satu hal: ORM.
ORM
Apa itu ORM? ORM merupakan singkatan dari Object Relational Mapper yang memungkinkan kita untuk berinteraksi dengan database. Intinya adalah layer penghubung dari aplikasi menuju database, kita gak perlu lagi menulis sql manual tapi cukup menulis python saja.
Lalu bedanya ORM ini dengan Model dan Migration di tulisan sebelumnya apa? Untuk menjawab itu mari baca lagi basic statement SQL
DDL & DML
Saat belajar database kita akan dikenalkan kepada dua basic statement SQL DDL dan DML, fungsi dua statement itu berbeda pastinya:
DDL (Data Definition Language): Sesuai namanya statement yang termasuk DDL adalah statement/query yang berhubungan tentang mendefinisikan tabel, mengubah tabel. Contoh sql DDL seperti create dan alter
CREATE TABLE <table name> ( <attribute name 1> <data type 1>, ... <attribute name n> <data type n>); ALTER TABLE <table name> ADD CONSTRAINT <constraint name> PRIMARY KEY (<attribute list>); DROP TABLE <table name>; ALTER TABLE <table name> DROP CONSTRAINT <constraint name>;
Model dan Migration asumsi saya berada di level ini, model kita mendefinisikan tabel dan migration membuat tabel di database.
DML (Data Manipulation Language): Query yang termasuk DML adalah query yang umumnya terkait kepada manipulasi data di tabel. Contohnya seperti insert, update, delete atau paling gampangnya CRUD.
ORM ini umumnya atau seringnya digunakan di level ini.
Contoh
Di bawah ini kita coba melakukan operasi-operasi DML di ORM dan dibandingkan dengan bagaimana kalau kita menulis query sql. Di sini saya menggunakan model category dari tulisan sebelumnya
Mari kita gunakan django shell, ketikan perintah berikut di root folder projek django
python manage.py shell
Select
Select adalah perintah untuk menampilkan data, di SQL kita akan menulis seperti ini
select * from blog_category
Versi ORM
from blog.models import Category Category.objects.all() //akan menghasilkan seperti berikut <QuerySet [<Category: Default>, <Category: Daily>, <Category: Tech>, <Category: Category 1>, <Category: Category 2>, <Category: Category 3>, <Category: Category 4>, <Category: Category 5>, <Category: Category 6>, <Category: Category 7>, <Category: Category 8>, <Category: Category 9>, <Category: Category 10>, <Category: Category 11>, <Category: Category 12>, <Category: Category 13>, <Category: Category 14>]>
Filter atau Pencarian
Salah satu fungi select lainnya adalah melakukan pembatasan data yang ditampilkan, di SQL ini biasnaya dimulai dengan where
, sedangkan di Django ORM ini bisa menggunakan .filter()
atau .get()
Di bawah ini adalah beberapa opsi pencarian yang biasa saya gunakan atau tepatnya yang paling sering saya temui.
Contoh dasar pencaraian menggunakan query SQL
select * from blog_category
Itu sama dengan
Category.objects.all()
Mencari berdasarkan field
Misal kita ingin mencari category dengan nama tertentu, maka di query sql akan seperti berikut
select * from blog_category where name = "some name"
saat kita terjemahkan kepada ORM maka seperti ini
Category.objects.filter(name="some name") atau Category.objects.get(name="some name")
Mencari nama yang mengadung kata tertentu
SQL
select * from blog_category where LIKE "%some name%"
ORM
Category.objects.filter(name__contains="some name") atau Category.objects.get(name__contains="some name")
Perintah di atas akan mencari di field nama dengan nilai yang yang memiliki/mengandung “some name”
Kita juga bisa mencari dengan beragam field seperti
Category.objects.filter(name="some name", slug="some-name")
Perintah di atas itu sama dengan
Select * from blog_category where field="same name" and slug="some-slug"
Fungsi dalam field
Di atas sudah ada contoh “fungsi” dalam field yaitu contains
dan icontains
tapi ORM punya lebih dari itu, beberapa yang sering saya gunakan
fungsi | penjelasan | contoh |
---|---|---|
contains | mencari yang mengandung kata yang dicari | name__contains=”filter” |
icontains | mencari yang mengandung kata yang dicari tapi incasesensitive | name_icontains=”filter” |
gt | greater than, mencari nilai yang lebih besari dari input | count__gt=2 |
gte | greater than equal, mencari nilai yang lebih besar atau sama dengan input | count__gte=2 |
lt | less than, mencari nilai yang lebih kecil | count__lt=2 |
lte | less than equal, mencari nilai yang lebih kecil atau sama dengan input | count__lte=2 |
Perhatikan pada contoh, setiap “fungsi” selalu diawali dengan dua underscore (__). Untuk lebih banyak contoh bisa lihat di sini [https://docs.djangoproject.com/en/4.0/ref/models/querysets/ ]
Menariknya lagi kita bisa mencari model dari foreignkeynya langsung, formatnya masih sama cukup disambugkan saja, misal dalam contoh menggunakan model content, kita ingin mencari semua konten yang memiliki kategory yang mengandung nama “blog” misalnya
Content.objects.filter(category__name__icontains="blog")
Satu lagi, perhatikan contoh sebelumnya, dalam pencarian kita bisa menggunakan dua cara antara filter()
atau get()
lantas apa bedanya?
Filter: Selalu akan memunculkan result dalam bentuk list berapapun data yang yang ada
Get: Selalu berasumsi bahwa data yang akan dimunculkan hanya satu, sehingga ketika kita menggunakan get dan ternyata object yang dicari menghasilkan lebih dari satu, akan menghasilkan error
MultipleObjectsReturned: get() returned more than one
Related name
class Category(models.Model): ..fields di category class Content(models.Model): category = models.ForeignKey(Category, related_name="content", on_delete=models.CASCADE )
Perhatikan contoh model di tulisan sebelumnya, di model yang berelasi saya menambahkan property related_name, fungsinya untuk apa? Sederhananya fungsinya itu untuk mepermudah memanggil “child” dari “parentnya”.
Jika dari content ingin mengakses kategory bisa dengan mudah seperti ini
content = Content.objects.get(id=1) category = conten.category ## output <Category >
Lalu bagaimana jika kita ingin mencari seperti berikut, munculkan semua konten dari kategori 1 misalnya
category = Category.objects.get(id=1) contens = category.content.all()
Create
Salah satu fungsi yang sering dipakai dalam operasional CRUD adalah create atau insert
create = Category(name="insert", slug="insert-1") create.save()
atau kalau kita punya dict yang keynya merupkan nama field bisa dipersingkat seperti ini
data = {“name”: “insert dict”, “slug”=”slug-dict”} create = Category(**data) create.save()
Update
Sesuai namanya, ini untuk mengubah data
get = Category.objects.get(id=1) get.name = “new name” get.save()
Delete
Untuk menghapus mirip dengan update tapi kita ubah saja method yang dipanggilnya
get = Category.objects.get(id=1) get.delete()
Lazy Loading
Django orm sendiri menerapkan lazy loading, kalau kita copas langsung dari dokumentasi
the results of a
QuerySet
aren’t fetched from the database until you “ask” for them
Contoh
>>> q = Entry.objects.filter(headline__startswith="What") --> belum manggil ke database >>> q = q.filter(pub_date__lte=datetime.date.today()) --> belum manggil >>> q = q.exclude(body_text__icontains="food") --> belum manggil >>> print(q) --> baru manggil ke database
Sepertinya segitu dulu untuk django orm, sampai jumpa.
referensi:
https://docs.djangoproject.com/en/3.2/topics/db/queries/#querysets-are-lazy
https://web.csulb.edu/colleges/coe/cecs/dbdesign/dbdesign.php?page=sql/ddldml.php