Di tutorial sebelumnya, kita sudah belajar mengelola database SQLite dengan modul sqlite3 bawaan Python. Menulis query SQL mentah memang fleksibel, tapi begitu aplikasi makin besar, kode jadi rawan error karena salah ketik nama kolom atau lupa menutup tanda kutip. Di sinilah SQLAlchemy masuk: library paling populer di ekosistem Python untuk bekerja dengan database lewat pendekatan Object Relational Mapping (ORM). Dalam tutorial ini kamu akan belajar SQLAlchemy dari nol sampai bisa melakukan CRUD lengkap beserta relasi antar tabel.
Apa Itu SQLAlchemy dan Kenapa Kamu Perlu Menggunakannya?
SQLAlchemy adalah toolkit SQL dan ORM untuk Python. ORM memungkinkan kamu memetakan tabel database menjadi class Python, dan baris data menjadi objek. Dengan kata lain, kamu berinteraksi dengan database menggunakan sintaks Python biasa, bukan string SQL. Beberapa keuntungan utamanya:
- Aman dari SQL injection — parameter query otomatis di-escape.
- Portable — ganti database dari SQLite ke PostgreSQL cukup dengan mengubah satu baris koneksi.
- Lebih mudah dibaca — relasi antar tabel diekspresikan lewat atribut objek, bukan
JOINmanual. - Terintegrasi baik dengan framework seperti Flask dan FastAPI.
Instalasi SQLAlchemy
Instalasi cukup dengan satu perintah. Pastikan kamu sudah berada di dalam virtual environment (kamu bisa pakai uv atau venv):
pip install sqlalchemy
Kita akan menggunakan SQLite pada tutorial ini karena tidak butuh server eksternal — SQLAlchemy otomatis bisa menggunakannya tanpa install tambahan.
Membuat Engine dan Koneksi ke Database
Langkah pertama adalah membuat engine, yaitu objek yang mengelola koneksi ke database. URL koneksi mengikuti pola dialek+driver://. Untuk SQLite, kita cukup menulis nama file database-nya:
from sqlalchemy import create_engine
# echo=True menampilkan query SQL yang dijalankan (berguna saat belajar)
engine = create_engine("sqlite:///perpustakaan.db", echo=False)
Mendefinisikan Model dengan Declarative Base
Model adalah class Python yang merepresentasikan tabel. Kita akan membuat dua tabel dengan relasi one-to-many: satu Penulis bisa punya banyak Buku. Gunakan style SQLAlchemy 2.0 dengan Mapped dan mapped_column agar lebih eksplisit dan terdukung type checker:
from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Penulis(Base):
__tablename__ = "penulis"
id: Mapped[int] = mapped_column(primary_key=True)
nama: Mapped[str] = mapped_column(String(100), nullable=False)
# relasi: satu penulis punya banyak buku
buku = relationship("Buku", back_populates="penulis")
def __repr__(self):
return f"<Penulis(nama='{self.nama}')>"
class Buku(Base):
__tablename__ = "buku"
id: Mapped[int] = mapped_column(primary_key=True)
judul: Mapped[str] = mapped_column(String(200), nullable=False)
tahun_terbit: Mapped[int]
penulis_id: Mapped[int] = mapped_column(ForeignKey("penulis.id"))
# relasi: setiap buku punya satu penulis
penulis = relationship("Penulis", back_populates="buku")
def __repr__(self):
return f"<Buku(judul='{self.judul}')>"
Perhatikan ForeignKey("penulis.id") pada kolom penulis_id. Ini yang mendefinisikan relasi antar tabel di level database, sedangkan relationship() memungkinkan kita mengakses objek terkait lewat atribut Python (misalnya buku.penulis.nama).
Membuat Tabel di Database
Setelah model didefinisikan, buat tabelnya dengan create_all(). Perintah ini hanya membuat tabel yang belum ada, jadi aman dijalankan berulang kali:
Base.metadata.create_all(engine)
Tips: create_all() tidak akan memperbarui struktur tabel yang sudah ada. Untuk manajemen skema yang lebih matang (migration), gunakan Alembic — tool migration resmi dari proyek SQLAlchemy.
Operasi CRUD: Create, Read, Update, Delete
Semua operasi database dilakukan melalui Session, yaitu unit kerja yang mengelola transaksi. Pola yang disarankan adalah menggunakan sessionmaker dan context manager agar session otomatis tertutup dengan benar. Mari kita buat data pertama:
from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(bind=engine)
with SessionLocal() as session:
# CREATE: tambah penulis dan buku
penulis = Penulis(nama="Andrea Hirata")
session.add(penulis)
session.commit() # simpan penulis dulu agar dapat id
buku = Buku(judul="Laskar Pelangi", tahun_terbit=2005, penulis=penulis)
session.add(buku)
session.commit()
print(f"Buku tersimpan: {buku}")
Penting: perubahan hanya tersimpan ke database setelah kamu memanggil session.commit(). Kalau lupa, data akan hilang begitu session ditutup.
Sekarang mari baca, perbarui, dan hapus data:
from sqlalchemy import select
with SessionLocal() as session:
# READ: ambil semua buku
semua_buku = session.scalars(select(Buku)).all()
for b in semua_buku:
print(f"{b.judul} oleh {b.penulis.nama}")
# UPDATE: ubah tahun terbit
buku = session.scalars(select(Buku).where(Buku.judul == "Laskar Pelangi")).one()
buku.tahun_terbit = 2005
session.commit()
# DELETE: hapus buku
session.delete(buku)
session.commit()
Query Data dengan Filter dan Ordering
SQLAlchemy 2.0 menganjurkan gaya query select() yang mirip SQL asli. Kamu bisa menggabungkan filter, pengurutan, dan limit dengan mudah:
with SessionLocal() as session:
# Filter: buku terbit tahun 2000 ke atas, urut berdasarkan judul
hasil = session.scalars(
select(Buku)
.where(Buku.tahun_terbit >= 2000)
.order_by(Buku.judul)
.limit(10)
).all()
for b in hasil:
print(b.judul, b.tahun_terbit)
# Hitung jumlah buku
total = session.scalar(select(func.count()).select_from(Buku))
print(f"Total buku: {total}")
Relasi Antar Tabel (One-to-Many)
Berkat relationship() yang sudah kita definisikan di model, mengambil data relasi jadi sangat natural — tanpa menulis JOIN sama sekali:
with SessionLocal() as session:
penulis = session.scalars(
select(Penulis).where(Penulis.nama == "Andrea Hirata")
).one()
# akses semua buku milik penulis ini
for b in penulis.buku:
print(f"- {b.judul} ({b.tahun_terbit})")
# dan sebaliknya: dari buku ke penulisnya
buku = session.scalars(select(Buku)).first()
print(buku.penulis.nama)
SQLAlchemy otomatis menjalankan query tambahan yang dibutuhkan saat kamu mengakses penulis.buku atau buku.penulis — ini disebut lazy loading.
Kesimpulan
Selamat! Kamu sudah memahami fondasi SQLAlchemy ORM: membuat engine, mendefinisikan model, melakukan CRUD, menulis query dengan select(), dan mengelola relasi antar tabel. Keterampilan ini sangat berguna ketika membangun API, misalnya dengan FastAPI yang sering dipadukan dengan SQLAlchemy. Untuk memastikan kode kamu bebas bug, biasakan menulis test dengan pytest. Selamat berkoding!