Framework 27 Aug 2026 51 views 0 komentar

Belajar Flask untuk Pemula - Membangun Web App Python dengan Jinja2 dan MySQL

Belajar Flask untuk Pemula - Membangun Web App Python dengan Jinja2 dan MySQL

Dulu saya males banget belajar web framework. Laravel terasa berat, Django penuh magic, dan dokumentasinya panjang banget buat pemula. Sampai akhirnya saya nemu Flask: micro-framework Python yang kecil, simpel, dan bikin saya paham cara kerja web dari bawah. Kalau kamu lagi nyari framework pertama yang nggak bikin pusing, artikel ini buat kamu.

Flask itu bukan cuma buat belajar lho. Banyak production app yang jalan pakai Flask, mulai dari API internal sampai dashboard perusahaan. Ukurannya kecil, tapi bisa tumbuh sesuai kebutuhan. Di artikel ini saya ajak kamu bikin web app lengkap: routing, template Jinja2, form, CRUD dengan MySQL, login sederhana, sampai deploy ke VPS. Semua langkahnya saya tulis dari pengalaman nyata, lengkap dengan error yang sering muncul.

Kenapa Flask dan Bukan Framework Lain?

Flask disebut micro-framework karena intinya kecil. Nggak ada ORM bawaan, nggak ada admin panel, nggak ada autentikasi siap pakai. Justru itu kelebihannya: kamu belajar setiap konsep secara eksplisit. Setelah paham Flask, pindah ke Django atau FastAPI jadi jauh lebih gampang karena fondasinya sudah kuat.

  • Ringan dan cepat start: project pertama bisa jalan dalam 5 menit.
  • Python: kalau kamu sudah familiar dengan Python, belajar Flask hampir tanpa kurva.
  • Fleksibel: mau bikin REST API, web app server-rendered, atau dashboard, Flask bisa semua.
  • Ekosistem dewasa: Flask sudah ada sejak 2010, dokumentasi lengkap, dan komunitasnya besar.
  • Job market: banyak perusahaan Indonesia yang stack-nya Python + Flask untuk internal tools.

Perbandingan cepat: Django itu "battery included" - semua sudah disediakan, kamu tinggal pakai. Flask itu "bring your own" - kamu yang rakit. Buat belajar, pendekatan Flask bikin kamu ngerti alurnya. Buat production, Flask cukup stabil kalau dirawat dengan baik.

Persiapan Project: Virtual Environment dan Instalasi

Langkah pertama yang wajib: pakai virtual environment. Saya pernah males bikin venv dan berakhir dengan dependency conflict yang bikin pusing seminggu. Python 3.8 ke atas sudah punya venv bawaan, jadi nggak perlu install apa-apa.

mkdir flask-blog
cd flask-blog
python3 -m venv venv
source venv/bin/activate
pip install flask flask-sqlalchemy pymysql

Perintah source venv/bin/activate mengaktifkan environment, jadi semua package terisolasi di folder project. Cek instalasi dengan perintah berikut:

python -c "import flask; print(flask.__version__)"

Kalau muncul versi Flask, berarti siap. Saya selalu cek versi dulu sebelum nulis kode, biar tahu package-nya benar-benar keinstall.

Hello World dan Routing

Buat file app.py dengan isi paling sederhana:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, Flask!"

if __name__ == "__main__":
    app.run(debug=True)

Jalankan dengan python app.py, buka http://127.0.0.1:5000, dan kamu akan lihat "Hello, Flask!". Decorator @app.route adalah cara Flask memetakan URL ke fungsi. Setiap URL baru tinggal tambah satu fungsi dengan decorator yang sama.

Routing di Flask mendukung parameter dinamis. Contohnya halaman profil user:

@app.route("/user/<username>")
def profile(username):
    return f"Profil: {username}"

Buka /user/budi, maka muncul "Profil: budi". Di sinilah bedanya dengan framework statis: URL kamu jadi dinamis tanpa konfigurasi tambahan. Buat blog, pola ini dipakai untuk halaman post per slug.

Template Jinja2: Pisahkan HTML dari Logika

Return string HTML langsung di dalam Python itu jelek dan susah dirawat. Flask pakai Jinja2, template engine bawaan yang memisahkan tampilan dari logika. Buat folder templates/ dan file base.html sebagai layout utama:

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Flask App{% endblock %}</title>
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
    <nav><a href="/">Home</a></nav>
    {% block content %}{% endblock %}
</body>
</html>

Perhatikan saya menulis &lt; dan &gt; untuk tag HTML di dalam contoh kode. Itu penting karena konten artikel dirender sebagai HTML, dan tag mentah akan dieksekusi browser. Di file asli kamu, tulis tag HTML biasa.

Lalu buat home.html yang mewarisi layout:

{% extends "base.html" %}
{% block title %}Halaman Utama{% endblock %}
{% block content %}
<h1>Selamat Datang</h1>
<p>Ini halaman utama Flask app pertama saya.</p>
{% endblock %}

Di controller, render template dengan render_template:

from flask import render_template

@app.route("/")
def home():
    return render_template("home.html", title="Halaman Utama")

Jinja2 juga punya loop dan conditional. Buat daftar artikel, tinggal kirim list dari Python dan loop di template:

{% for post in posts %}
<article>
    <h2>{{ post.title }}</h2>
    <p>{{ post.excerpt }}</p>
</article>
{% endfor %}

Pola ini persis yang dipakai blog-blog production. Data dari database, tampilan di template, logika tetap di Python.

Form dan Flash Messages

Web app tanpa form itu seperti motor tanpa bensin. Flask menangani form dengan mudah: data POST bisa diambil dari request.form. Tambahkan halaman kontak sederhana:

from flask import request, flash, redirect, url_for

@app.route("/contact", methods=["GET", "POST"])
def contact():
    if request.method == "POST":
        nama = request.form.get("nama")
        pesan = request.form.get("pesan")
        if not nama or not pesan:
            flash("Nama dan pesan wajib diisi!", "error")
        else:
            flash(f"Terima kasih {nama}, pesan kamu terkirim!", "success")
        return redirect(url_for("contact"))
    return render_template("contact.html")

flash() menyimpan pesan satu kali request, lalu ditampilkan di template. Ini cara standar memberi feedback ke user tanpa query string yang jelek. Di template, tampilkan dengan loop:

{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}

Pola POST-redirect-GET di atas penting: setelah form diproses, selalu redirect biar refresh browser nggak mengirim ulang data. Ini kebiasaan yang menyelamatkan kamu dari duplikasi data di database.

Database dengan Flask-SQLAlchemy dan MySQL

Bagian ini yang paling sering bikin orang nyerah, padahal nggak sesulit itu. Saya pakai Flask-SQLAlchemy supaya nggak nulis query mentah. Konfigurasi koneksi MySQL:

from flask_sqlalchemy import SQLAlchemy

app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://user:password@localhost/flask_blog?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

Ganti user:password dengan kredensial MySQL kamu, dan buat database-nya dulu:

CREATE DATABASE flask_blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Lalu definisikan model. Model adalah class Python yang mewakili tabel:

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, server_default=db.func.now())

    def __repr__(self):
        return f"<Post {self.title}>"

Buat tabelnya dengan perintah di Python shell:

python -c "from app import db; db.create_all()"

Setelah tabel jadi, operasi CRUD jadi sesimpel ini:

# Create
post = Post(title="Belajar Flask", content="Isi artikel...")
db.session.add(post)
db.session.commit()

# Read
posts = Post.query.order_by(Post.created_at.desc()).all()

# Update
post = Post.query.get(1)
post.title = "Judul Baru"
db.session.commit()

# Delete
db.session.delete(post)
db.session.commit()

Perhatikan pola commit: semua perubahan dikumpulkan di session, lalu commit() sekali. Kalau ada error di tengah, pakai db.session.rollback() biar data nggak setengah jadi. Saya selalu bungkus operasi tulis dalam try-except di production.

Login Sederhana dengan Session

Autentikasi penuh itu topik panjang, tapi untuk kebutuhan dasar, session Flask sudah cukup. Setelah user login, simpan user id di session:

from flask import session
import secrets

app.secret_key = secrets.token_hex(16)

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        # Di production: hash password dengan werkzeug.security
        if username == "admin" and password == "rahasia":
            session["user_id"] = 1
            return redirect(url_for("dashboard"))
        flash("Username atau password salah!", "error")
    return render_template("login.html")

Jangan pernah simpan password plaintext. Pakai generate_password_hash() dan check_password_hash() dari werkzeug.security. Proteksi halaman admin dengan cek session di awal fungsi:

@app.route("/dashboard")
def dashboard():
    if "user_id" not in session:
        return redirect(url_for("login"))
    return render_template("dashboard.html")

Untuk project yang lebih serius, lihat Flask-Login atau Flask-JWT-Extended. Tapi untuk memahami konsep, session manual ini justru bagus karena kamu lihat apa yang terjadi di balik layar.

Struktur Project yang Rapi

Waktu project mulai besar, satu file app.py bakal berantakan. Saya pernah punya app.py 800 baris dan susah banget nyari bug. Solusinya: pisah-pisah sesuai tanggung jawab. Ini struktur yang saya pakai untuk project Flask ukuran menengah:

flask-blog/
|-- app.py
|-- models.py
|-- views.py
|-- templates/
|   |-- base.html
|   |-- home.html
|   `-- contact.html
|-- static/
|   |-- style.css
|   `-- script.js
|-- venv/
`-- requirements.txt

app.py cuma buat inisialisasi aplikasi dan mendaftarkan Blueprint. models.py berisi semua model database. views.py berisi semua route. Template dan static dipisah sesuai fungsinya. requirements.txt wajib ada: satu perintah pip install -r requirements.txt langsung menyiapkan environment di server baru, nggak perlu install satu-satu.

Untuk konfigurasi yang beda antara lokal dan production, jangan hardcode di kode. Pakai environment variable: app.config.from_prefixed_env() atau library python-dotenv. Dengan begitu kredensial database nggak pernah nyasar ke repository publik. Ini kebiasaan kecil yang menyelamatkan banyak orang dari kebocoran data.

Flask vs FastAPI vs Django: Pilih yang Mana?

Kalau kamu baca artikel ini, mungkin sempat bingung milih Flask, FastAPI, atau Django. Tiga-tiganya framework Python, tapi punya kepribadian yang beda:

  • Flask: micro-framework, minimalis, fleksibel. Cocok buat belajar, internal tools, dan project yang mau kontrol penuh. Template Jinja2 built-in, jadi enak buat web app server-rendered seperti yang kita buat di atas.
  • FastAPI: fokus ke API. Type hints, dokumentasi otomatis (Swagger UI), dan dukungan async. Lebih baru dan lebih cepat untuk pure API. Tapi nggak ada template engine bawaan, jadi kurang pas buat web app klasik dengan halaman HTML.
  • Django: all-in-one. ORM, admin panel, autentikasi, migrasi - semua sudah disediakan. Cocok buat project besar yang butuh fitur lengkap dengan cepat. Tapi kurva belajarnya curam, dan kadang terasa terlalu berat untuk project kecil.

Verdict saya: mulai dari Flask. Kamu belajar konsep web tanpa disembunyikan framework. Nanti kalau butuh API super cepat, pindah ke FastAPI tinggal adaptasi. Kalau butuh fitur lengkap, Django tinggal dipelajari - dan pemahaman soal HTTP, session, dan ORM yang kamu dapat dari Flask bakal sangat membantu. Framework hanyalah alat; konsep yang kamu kuasai yang bertahan.

Deploy ke VPS: Gunicorn dan Nginx

Ini bagian yang paling saya suka: aplikasi kamu akhirnya bisa diakses orang lain. Development server Flask (app.run) cuma untuk lokal. Di production, pakai Gunicorn sebagai WSGI server, dan Nginx sebagai reverse proxy.

Pertama, install Gunicorn dan buat file service systemd:

pip install gunicorn
# /etc/systemd/system/flask-app.service
[Unit]
Description=Flask App
After=network.target

[Service]
User=www-data
WorkingDirectory=/var/www/flask-blog
ExecStart=/var/www/flask-blog/venv/bin/gunicorn -w 3 -b 127.0.0.1:8000 app:app
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now flask-app

Lalu konfigurasi Nginx sebagai reverse proxy:

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /static/ {
        alias /var/www/flask-blog/static/;
    }
}

Catatan penting: file static dilayani Nginx langsung, bukan lewat Gunicorn. Ini menghemat resource karena Python nggak perlu memproses CSS dan gambar. Setelah konfigurasi, jalankan sudo nginx -t lalu reload. Jangan lupa pasang SSL dengan certbot biar dapat HTTPS gratis.

Troubleshooting yang Sering Muncul

Selama pakai Flask, ada beberapa error yang hampir pasti kamu temui:

  • ModuleNotFoundError: No module named 'flask' - venv belum aktif atau package belum keinstall. Jalankan source venv/bin/activate dulu.
  • OperationalError: Access denied for user - kredensial MySQL salah, atau user MySQL belum diberi hak akses ke database. Cek dengan GRANT ALL ON flask_blog.* TO 'user'@'localhost';
  • TemplateNotFound: home.html - file template harus ada di folder templates/ persis, termasuk subfolder. Periksa penulisan nama file, case sensitif.
  • Port 5000 sudah dipakai - jalankan dengan port lain: app.run(port=5001).
  • 502 Bad Gateway dari Nginx - Gunicorn mati atau bind address salah. Cek sudo journalctl -u flask-app -e untuk log-nya.
  • Data bertambah dua kali saat submit form - kamu lupa pola POST-redirect-GET. Setelah proses, selalu redirect(url_for(...)).
  • Session hilang setelah deploy - kemungkinan secret_key berubah setiap restart. Set nilai yang tetap lewat environment variable, jangan secrets.token_hex() di setiap boot.
  • CSRF token error - kalau pakai Flask-WTF, pastikan SECRET_KEY ter-set sebelum form divalidasi, dan form pakai form.hidden_tag().
  • Gambar atau CSS 404 setelah deploy - path static di template harus pakai url_for('static', filename='...'), bukan hardcode /static/..., supaya tetap benar walau aplikasi dipindah ke subfolder.

Kalau ketemu error aneh, langkah pertama saya selalu baca log lengkapnya, bukan nebak. Gunicorn dan Nginx dua-duanya punya log yang jelas. Error message Python juga biasanya sudah menunjuk baris persisnya.

Kesimpulan

Flask adalah pintu masuk terbaik ke web development pakai Python. Kecil, jelas, dan kamu belajar konsep web dari nol: routing, template, form, database, sampai deployment. Setelah lancar di sini, kamu bisa naik ke FastAPI untuk API, atau Django kalau butuh fitur lengkap.

Mulai dari project kecil dulu: bikin aplikasi catatan, to-do list, atau blog sederhana seperti yang kita buat di atas. Jangan langsung bikin aplikasi besar. Satu project selesai lebih berharga daripada sepuluh project setengah jadi.

Kalau kamu baru coba Flask setelah baca artikel ini, cerita dong di kolom komentar: project apa yang pertama kali mau kamu bangun? Atau kalau ada error yang bikin kamu mentok, tulis di sini juga, saya bantu cari solusinya.


Bagikan artikel ini:

Komentar (0)

Belum ada komentar. Jadilah yang pertama memberikan tanggapan!

Tinggalkan Komentar