앞 강에서 "브라우저가 서버에 요청한다"고 했죠. 그런데 서버 쪽에서는 누가 그 요청을 받을까요?
그 역할을 하는 프로그램이 웹 프레임워크이고, 파이썬에서 가장 배우기 쉬운 것이
Flask(플라스크)입니다.
우리가 만들 것의 전체 뼈대
이제부터 마지막 강까지, 우리는 DBMS 위에 올라선 풀스택 웹앱 하나를 짓습니다.
건물처럼 네 개의 층으로 되어 있어요. 각 층은 딱 한 가지 일만 합니다.
4층🎨 Bootstrap
보기 좋게 — 색·여백·카드·반응형
3층📄 Jinja2
데이터를 HTML로 — 반복·조건·상속
2층🧪 Flask
요청을 받고 판단 — 라우트·검증·계산
1층🗄️ SQLite3
진실을 보관 — 표·타입·트랜잭션
1층은 지난 강에서 지었습니다. 오늘은 2층이에요.
1층이 없으면 나머지 세 층은 모래 위의 집입니다. 그래서 데이터베이스가 먼저였던 거예요.
세상에서 가장 짧은 웹 서버
from flask import Flask
app = Flask(__name__)
@app.route("/") # 주소 "/" 로 요청이 오면
def hello(): # 이 함수를 실행해서
return "안녕하세요!" # 이 글자를 돌려준다
app.run(port=5000)
단 6줄입니다. @app.route(...)를 라우트(route)라고 부르는데,
"이 주소는 이 함수가 담당"이라는 이정표예요.
🎮 라우터 실험실 — 주소를 바꿔 가며 보내 보세요
아래는 진짜 라우팅 규칙으로 주소를 맞춰 보고, 여러분의 연습 DB에
실제 SQL을 실행하는 미니 서버입니다. 주소 한 글자만 바꿔도 담당 함수가 달라져요.
/api/products/2 와 /api/products/999 를 비교해 보세요. 하나는 200, 하나는 404입니다.
/api/products/abc — 왜 404일까요? <int:pid> 는 숫자만 받기 때문입니다.
주소는 그대로 두고 메서드만 DELETE로 바꿔 /api/products 에 보내 보세요. 405가 뜹니다.
"주소는 있는데 그 방법은 안 받는다"는 뜻이에요.
POST로 상품을 등록한 뒤 GET /api/products 로 확인해 보세요. 진짜로 늘어나 있습니다.
/ 와 /api/products 를 비교해 보세요. 같은 SELECT인데
하나는 HTML, 하나는 JSON입니다. 마지막 한 줄만 다르거든요.
라우터 실험실 — URL이 함수를 고르고, 함수가 SQL을 실행합니다
불러오는 중…
Flask가 DB를 여는 방법
라우트 함수 안에서 SQLite3를 열고, SQL을 실행하고, 결과를 받습니다. 세 줄이면 돼요.
import sqlite3
from flask import Flask, render_template
app = Flask(__name__)
def db():
conn = sqlite3.connect("shop.db")
conn.row_factory = sqlite3.Row # 결과를 딕셔너리처럼 다루기
return conn
@app.route("/")
def product_list():
conn = db()
rows = conn.execute("SELECT * FROM product ORDER BY id").fetchall()
conn.close()
return render_template("products.html", products=rows) # ← 3층으로 넘긴다
마지막 줄이 오늘의 핵심입니다. render_template은
"이 데이터를 가지고 화면을 만들어 줘"라고 3층(Jinja2)에게 넘기는 말이에요.
🖥️브라우저GET /
→
🧪Flask어느 함수가 처리할지 결정
→
🗄️SQLite3SELECT * FROM product
← 완성된 HTML ←
또 하나의 길 — JSON API
서버가 완성된 화면(HTML) 대신 데이터만(JSON) 돌려줄 수도 있습니다.
앱이나 자바스크립트가 화면을 직접 그릴 때 쓰는 방식이에요.
from flask import jsonify, request
@app.route("/api/products") # 데이터만 돌려주기
def api_products():
conn = db()
rows = conn.execute("SELECT * FROM product").fetchall()
conn.close()
return jsonify([dict(r) for r in rows])
@app.route("/api/products", methods=["POST"])
def api_add():
name = request.json["name"]
price = request.json["price"]
conn = db()
cur = conn.execute("INSERT INTO product (name, price) VALUES (?, ?)", (name, price))
conn.commit(); conn.close()
return jsonify({"id": cur.lastrowid}), 201
render_template (서버가 화면까지)
첫 화면이 빠르게 보인다
검색엔진이 내용을 읽는다
배우기 쉽다 — 우리가 갈 길
jsonify (데이터만)
모바일 앱과 같은 서버를 쓸 수 있다
화면 일부만 새로 그리기 좋다
프론트엔드 코드가 따로 필요
둘 다 DB에서 읽어 오는 부분은 완전히 같습니다. 달라지는 건 마지막 한 줄뿐이에요.
🤔 확인 문제
Flask 라우트 함수가 render_template("products.html", products=rows) 를 돌려주면 무슨 일이 일어날까요?
해설render_template은 데이터를 템플릿(틀)에 부어 완성된 HTML을 만듭니다. 브라우저는 DB의 존재조차 모른 채 결과 화면만 받아요. 다음 강에서 그 틀을 직접 씁니다.