4 min read

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