*모든 저작권은 IT WILL 이광호 선생님
LAB -10 Python Basic | Flask 웹 프로그래밍
<학습 목표>
1. 웹 서버의 이해
2. Restful API 의 이해
3. 데이터 조회 API
4. 데이터 입력/수정/삭제 API
1. 웹 서버의 이해
웹 서버에는 크게 두 주체가 존재함
요청을 보내는 클라이언트 (ex 소비자, 터미널, 웹브라우저) ,
요청을 처리하고 대응하는 서버 (ex 판매자 ,DB, 웹 서버)
플라스크는 불필요한 기능을 최소화한 "마이크로" "웹 프레임워크"
코드에 대한 기본 구조와 틀이 이미 정해져있음
Flask 프로그램 기본 구조
#Flask 프로그램의 기본 구조
#프로그램 최 상단에서 채키지 참조 처리와 Flask 메인 객체를 생성
# 프로그램 마지막에 생성한 Flask 메인 객체 가동
# [1] 패키지 참조
from flask import Flask, render_template
# [2] Flask 의 메인 객체를 생성 (__name__ 은 소스 파일의 이름)
app=Flask(__name__)
# [3] 웹 페이지 함수 구현하기 (url 요청에 실행될 함수를 연결하는 처리를 라우팅이라고 함)
@app.route("/hello")
def hello():
#웹 브라우저에 전달할 본문
html =""" Hello Flask!
This is Flask Wevbpage
"""
#웹 브라우저에게 문자열 전달
return html
#[4] Flask 웹 서버 가능
if __name__ =="__main__":
app.run(port=9091, debug= True)
flask 클래스로 app 객체 생성
app 에 필요한 항목들 넣어서 그걸 마지막에 실행 시킴
이 파일을 직접 실행
라우팅 - 이 웹페이지에 부여하고자 하는 url (주소에 함수들을 분배한다)
웹브라우저에 접속하면 그 밑에 있는 함수들이 실행

(소스코드에서는 줄바꿈을 했어도 브라우저에서는 줄바꿈을 처리하진 못함)
웹 브라우저가 식별할 수 있는 규칙에 맞춰 문자열 리턴하기
#Flask 프로그램의 기본 구조
#프로그램 최 상단에서 채키지 참조 처리와 Flask 메인 객체를 생성
# 프로그램 마지막에 생성한 Flask 메인 객체 가동
# [1] 패키지 참조
from flask import Flask, render_template
# [2] Flask 의 메인 객체를 생성 (__name__ 은 소스 파일의 이름)
app=Flask(__name__)
# [3-2] 웹 브라우저가 식별할 수 있는 규칙에 맞춘 문자열 리턴하기
@app.route("/world")
def world():
# 웹 브라우저가 인식할수 있는 특정한 형식을 갖춘 문자열 리턴
html =""" <h1> 안녕 플라스크!! </h1>
<p style = 'color: blue'> 첫 번쨰 플라스크 웹 페이지 </p>
"""
return html
#[4] Flask 웹 서버 가능
if __name__ =="__main__":
app.run(port=9091, debug= True)

이번엔 h 태그와 p style 이 적용되었음
별도로 구현된 프론트엔드 웹 페이지를 웹 브라우저에 전달하기
모든 프론트엔드 코드를 문자열로 리턴하는 것은 비효율 적이기 떄문에, 프론트엔드 개발자로부터 소스 코드를 전달받아 FLASK 작업 폴터의 특정 파일에 넣어두고, FLASK 가 이 파일을 읽어서 웹 브라우저에게 전달하게 하는것이 일반적
# [1] 패키지 참조
from flask import Flask, render_template
# [2] Flask 의 메인 객체를 생성 (__name__ 은 소스 파일의 이름)
app=Flask(__name__)
# [3-3] 별도로 구현된 프론트엔드 웹 페이지를 웹 브라우저에게 전달하기
@app.route("/myfood")
def myfood():
return render_template("myfood.html")
#[4] Flask 웹 서버 가능
if __name__ =="__main__":
app.run(port=9091, debug= True)

JSON 구조의 응답 결과 반환하기 (딕셔너리 데이터를 웹 브라우저에 전달)
#Flask 프로그램의 기본 구조
#프로그램 최 상단에서 채키지 참조 처리와 Flask 메인 객체를 생성
# 프로그램 마지막에 생성한 Flask 메인 객체 가동
# [1] 패키지 참조
from flask import Flask, render_template
# [2] Flask 의 메인 객체를 생성 (__name__ 은 소스 파일의 이름)
app=Flask(__name__)
#[3-4] JSON 구조의 응답 결과 반환하기 (딕셔너리 데이터를 웹 브라우저에 전달)
@app.route("/mydata")
def mydata():
mydict={"name":"LEE","age":24,"height":175,"weight":82}
return mydict
#[4] Flask 웹 서버 가능
if __name__ =="__main__":
app.run(port=9091, debug= True)

2.Restfull API의 이해
웹 상에 공개되어 있는 데이터에 접근하기 위한 표준 규격이 RESTFUL API
API 는 프로그램 간 데이터를 주고받기 위한 규칙과 약속이고
REST 는 웹에서 데이터를 효율적으로 주고받기 위한 설계 원칙

HTTP Method 에 작동 방식

PK 인 10101 이 마치 폴더 구조처럼 존재
HTTP GET 방식 (조회)
QUERYSTRING 방식의 전송으S GET 방식의 요청에서만 가능
URL 을 통해서 웹 서버에 특정 함수를 호출할 수 있지
이떄 데이터를 요청할 세부 사항을 파라미터, 즉 쿼리 스트링으로서 작성해서 호출할 수 있음

request.args.get() 이 부분이 있어야 백엔드에 함수에 파라미터 쓸 수 있는 요건이 충족되는 것과 같음

모든 데이터는 string 으로 들어오니까 형변환 해야함

엔드 포인트에서 확인해보면 아래와 왔음

get 방식을 제외한 나머지 방식은 웹 브라우저로 접근이 불가함
즉 post 이런 거는 웹 브라우저로 테스트 불가, 전문 테스트 프로그램 사용 필요
# restful api 의 이해
# [1] 패키지 참조
from flask import Flask, request
#[2] Flask 메인 객체 생성 (__name__ 은 이 소스 파일의 이름)
app =Flask(__name__)
# [3] GET 방식 요청에 따른 응답 결과 생성하기
#GET 방식의 데이터 수신
@app.route("/parameter",methods=["GET"])
def get():
#url 에 포함된 변수 추출
my_num1 =request.args.get('num1')
my_num2 =request.args.get('num2')
#클라이언트로부터 전달받은 모든 파라미터는 무조건 문자열인 것 주의해야함
sum1 = my_num1 + my_num2
sum2 = int(my_num1) + int(my_num2)
mydict ={
"expr" :"%s + %s" %(my_num1,my_num2),
"sum1":sum1,
"sum2":sum2
}
return mydict
# [4] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(port=9091,debug = True)

http://127.0.0.1:9091/parameter?num1=1000&num2=500
url 에 있는 파라미터를 인식해서 웹 서버를 호출하는 방식도 가능

> 다만 이렇게 쿼리 스트링으로 모든 변수를 URL에 노출시키기엔 URL 길이 제한이 있다보니 단점을 보완하기 위해서는 form 객체의 메서드를 사용할 수있음
HTTP POST, PUT, DELETE 방식의 파라미터 전달하기
쿼리 스트링을 활용하는건 GET 만 가능하니 다른 세 방식은 URL 에 노출하지 않느S HTTP HEADER 방식 사용 필요
methods 부분이랑 request.form.##

으로 수정
테스트 할 떄는 확장 프로그램 사용 필요
POST 방식
# restful api 의 이해
# [1] 패키지 참조
from flask import Flask, request
#[2] Flask 메인 객체 생성 (__name__ 은 이 소스 파일의 이름)
app =Flask(__name__)
# [3-2] POST 방식의 파라미터 처리하기
@app.route("/parameter",methods=["POST"])
def post():
x=request.form.get("x")
y=request.form.get("y")
z=int(x)*int(y)
return {
"expr":"%s*%s"%(x,y),
"z":z
}
# [4] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(port=9091,debug = True)

PUT 방식
# restful api 의 이해
# [1] 패키지 참조
from flask import Flask, request
#[2] Flask 메인 객체 생성 (__name__ 은 이 소스 파일의 이름)
app =Flask(__name__)
#[3-3] PUT 방식으로 데이터 수신하기
@app.route("/parameter",methods=["PUT"])
def put():
a=request.form.get("a")
b=request.form.get("b")
c=int(a)-int(b)
return {
"expr":"%s-%s"%(a,b),
"c":c
}
# [4] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(port=9091,debug = True)

DELETE 방식
# restful api 의 이해
# [1] 패키지 참조
from flask import Flask, request
#[2] Flask 메인 객체 생성 (__name__ 은 이 소스 파일의 이름)
app =Flask(__name__)
#[3-4] DELETE 방식의 데이터 수신
@app.route("/parameter",methods=["DELETE"])
def delete():
m=request.form.get("m")
n=request.form.get("n")
o=int(m)/int(n)
return {
"expr":"%s/%s"%(m,n),
"o":o
}
# [4] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(port=9091,debug = True)

PATH 파라미터 전달하기
PATH 형식으로 파라미터를 전달하는건 모든 METHOD(Get,post,put,delete) 에서 사용 가능
URL 에 변수를 폴더 경로인 것 처럼 포함하는 방식

# restful api 의 이해
# [1] 패키지 참조
from flask import Flask, request
#[2] Flask 메인 객체 생성 (__name__ 은 이 소스 파일의 이름)
app =Flask(__name__)
#[3-5] PATH 파라미터 처리하기 (GET,POST,PUT,DELETE 모두 공통)
@app.route("/parameter/<myname>/<myage>", methods=['GET'])
def path_params(myname, myage):
msg = "안녕하세요 {name}님. 당신은 {age}세 입니다."
return {
"msg": msg.format(name=myname, age=myage)
}
# [special] 예외 발생 시 호출되는 함수 정의 (전역 try except 효과)
@app.errorhandler(Exception)
def error_handling(error):
return({"message":str(error)},500)
# [4] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(port=9091,debug = True)

데이터 조회 API
위에서 실행한 함수들마다 데이터베이스 접속해줘야하고, 접속 후엔 해제까지 해줘야함
이 부분을 반복하기 쉽게 모듈로 만들어 주기
<접속/접속 끊기 모듈화>
# [1/3] 모든 함수에서 공통적으로 사용하는 기능 모듈화
# 데이터베이스 접속 정보
from sqlalchemy import create_engine
config = {
'username': 'root', # 접속할 사용자 이름
'password': '1234', # 접속할 사용자의 비밀번호
'hostname': 'localhost', # 접속할 시스템 주소 (내 컴퓨터인 경우 localhost)
'port': '9090', # 설치시 설정한 포트번호 (기본값: 3306)
'database': 'myschool', # 사용할 데이터베이스 이름
'charset': 'utf8mb4' # 한글 깨짐 방지 (데이터베이스의 설정과 동일하게 지정)
}
conn = None # 데이터베이스 접속 객체에 대한 전역 변수 선언
# [2/3] 모든 함수에서 공통적으로 사용하는 기능 모듈화
# 데이터베이스 접속 함수
def connect():
global conn # 함수 외부의 변수를 함수 안으로 끌고 들어옴
con_str_tpl = "mariadb+pymysql://{username}:{password}@{hostname}:{port}/{database}?charset={charset}"
con_str = con_str_tpl.format(**config)
engine = create_engine(con_str)
conn = engine.connect()
return conn
# 데이터베이스 접속 해제 함수
def disconnect():
global conn # 함수 외부의 변수를 함수 안으로 끌고 들어옴
if conn != None:
conn.close()
# [3/3] 모듈 테스트 -->> 에러 없이 실행되면 정상 (출력결과 없음)
# 모듈 테스트
if __name__ == "__main__":
connect()
disconnect()
<연결된 웹 서버에서 sql 을 통해 단일행 및 다중행 가져오기>
# [1] 패키지 참조
from flask import Flask, request
from sqlalchemy import text
import datetime as dt
from mylibrary import MyDB
# [2] Flask 메인 객체 생성
app = Flask(__name__) # __name__ 은 이 소스파일의 이름
app.json.sort_keys = False # 출력 결과의 JSON 정렬 방지
# [3-1] 다중행 조회 구현
@app.route("/departments", methods=['GET'])
def get_list():
# 실행할 SQL문 정의
sql = text("SELECT id, dname, loc, phone, email FROM departments")
conn = MyDB.connect() # DB 접속
result = conn.execute(sql) # SQL문을 실행하여 결과 객체 받기
MyDB.disconnect() # DB 접속 해제
# 단일행 조회에 대한 결과 집합 추출하기
resultset = result.mappings().all()
# 반복문으로 탐색하면서 개별 레코드틀 딕셔너리로 변환해야 함
for i in range(0, len(resultset)):
resultset[i] = dict(resultset[i])
# 결과 반환하기
return {
"result": resultset,
"timestamp": dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# [3-2] 단일행 조회 구현
# 단일행의 경우 결과 값이 0개 아니면 1개이기 때문에 마지막 return 에서 resultset[0] 처리
@app.route("/departments/<id>", methods=['GET'])
def get_item(id):
# SQL문 정의
sql = text("""SELECT id, dname, loc, phone, email, established, homepage
FROM departments WHERE id=:id""")
conn = MyDB.connect() # DB 접속
result = conn.execute(sql, {"id": id}) # SQL문을 실행하여 결과 객체 받기
MyDB.disconnect() # DB 접속 해제
# 단일행 조회에 대한 결과 집합 추출하기
resultset = result.mappings().all()
return {
"result": dict(resultset[0]), # 조회 결과에 대한 딕셔너리 변환
"timestamp": dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# [4] 전역 예외 처리
@app.errorhandler(Exception)
def error_handling(error):
MyDB.disconnect() # 데이터베이스 접속 해제
return {
'message': "".join(error.args),
'timestamp': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}, 500
# [5] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(host='127.0.0.1', port=9091, debug=True)
<결과1. 단일행 (상세 페이지)>

<결과2. 다중행>

4. 데이터 저장 /수정/삭제 API
4-1 데이터 저장
RESTFUL 은 URL 1개에 METHODS 를 바꿔가는 것
RESTFUL 은 일종의 테이블이고, 이 테이블에서 데이터를 입력 수정 삭제 조회할 수 있는 것
# [1] 패키지 참조
from flask import Flask, request
from sqlalchemy import text
import datetime as dt
from mylibrary import MyDB
# [2] Flask 메인 객체 생성
app = Flask(__name__) # __name__ 은 이 소스파일의 이름
app.json.sort_keys = False # 출력 결과의 JSON 정렬 방지
#[3] 생략
# [4] 전역 예외 처리
@app.errorhandler(Exception)
def error_handling(error):
MyDB.disconnect() # 데이터베이스 접속 해제
return {
'message': "".join(error.args),
'timestamp': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}, 500
# =================================================================
# [5-1] 데이터 입력 API
#데이터 저장하기
@app.route("/departments",methods=["POST"])
def post ():
#DB 접속하기
conn = MyDB.connect()
#1) 데이터 저장하기
dname = request.form.get("dname")
loc = request.form.get("loc")
phone = request.form.get("phone")
email = request.form.get("email")
established = request.form.get("established")
homepage = request.form.get("homepage")
# SQL문 정의
sql = text("""INSERT INTO departments (dname, loc, phone, email, established, homepage)
VALUES (:dname, :loc, :phone, :email, :established, :homepage)""")
# POST 파라미터를 SQL에 맵핑하기 위해 딕셔너리로 묶음
params = {
"dname": dname, "loc": loc, "phone": phone, "email": email,
"established": established, "homepage": homepage
}
conn.execute(sql, params) # SQL문 실행하기 -> 자동 트랜잭션
conn.commit() # 변경사항을 데이터베이스에 영구 저장
#2) 데이터 저장 결과 조회하기
#생성된 PK 값 추출하기
pk_result = conn.execute(text("SELECT LAST_INSERT_ID()"))
pk = pk_result.scalar()
sql = text("""SELECT id, dname, loc, phone, email, established, homepage
FROM departments WHERE id=:id""")
result = conn.execute(sql, {"id": pk}) #SQL 문을 실행하여 결과 객체 받기
resultset = result.mappings().all() #단일행 조회에 대한 결과 집합 추출하기
#DB 접속 해제
MyDB.disconnect()
#응답 결과 반환하기
return {
"result": dict(resultset[0]),
"timestamp": dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# =================================================================
# [6] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(host='127.0.0.1', port=9091, debug=True)

지금 쓰는건 SQLalchemy > 자동으로 트랜젝션 진행되고,오류 발생해도 전역적으로 적용된다
보통 데이터를 insert 하면 바로 select 이 작용하니까
방금 마지막에 insert 된 것을 select 한다
(ex) 리뷰 쓰면 리뷰 바로볼 수있듯이
==================
4-2 데이터 수정
# [1] 패키지 참조
from flask import Flask, request
from sqlalchemy import text
import datetime as dt
from mylibrary import MyDB
# [2] Flask 메인 객체 생성
app = Flask(__name__) # __name__ 은 이 소스파일의 이름
app.json.sort_keys = False # 출력 결과의 JSON 정렬 방지
# [4] 전역 예외 처리
@app.errorhandler(Exception)
def error_handling(error):
MyDB.disconnect() # 데이터베이스 접속 해제
return {
'message': "".join(error.args),
'timestamp': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}, 500
# =================================================================
# [5-2] 데이터 수정 API
@app.route("/departments/<id>",methods=["PUT"])
def put(id):
#DB 접속하기
conn=MyDB.connect()
# 1) 데이터 수정하기
# PUT 파라미터 수신하기
dname = request.form.get("dname")
loc = request.form.get("loc")
phone = request.form.get("phone")
email = request.form.get("email")
established = request.form.get("established")
homepage = request.form.get("homepage")
#SQL 문 정의
sql = text("""UPDATE departments SET
dname=:dname, loc=:loc, phone=:phone, email=:email, established=:established, homepage=:homepage
WHERE id=:id""")
# PUT 파라미터를 sql에 맵핑하기 위해 딕셔너리로 묶음 -> where 절에 사용할 id 값은 path 파라미터
params = {
"id": id, "dname": dname, "loc": loc, "phone": phone,
"email": email, "established": established, "homepage": homepage
}
conn.execute(sql, params) # sql 문 실행하기 > 자동 트랜젝션
conn.commit()
# 2) 데이터 수정 결과 조회하기
#sql 문 정의
sql = text("""SELECT id, dname, loc, phone, email, established, homepage
FROM departments WHERE id=:id""")
# sql 문을 시랳ㅇ하여 결과 객체 받기
result = conn.execute(sql, {"id": id})
# 단일행 조회에 대한 결과 집합 추출하기
resultset = result.mappings().all()
#DB 접속 해제
MyDB.disconnect()
#응답 결과 반환하기
return {
"result": dict(resultset[0]),
"timestamp": dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# =================================================================
# [6] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(host='127.0.0.1', port=9091, debug=True)

데이터 수정과 삭제는 where 절이 꼭 걸려있어야함
특히 pk 에 대해서만 씀
> restfulapi 에서는 path 로 받음
pk 가 아닌 애들은 request.form.get() 으로 따로 받아와야함
====================
4-3 데이터 삭제
# [1] 패키지 참조
from flask import Flask, request
from sqlalchemy import text
import datetime as dt
from mylibrary import MyDB
# [2] Flask 메인 객체 생성
app = Flask(__name__) # __name__ 은 이 소스파일의 이름
app.json.sort_keys = False # 출력 결과의 JSON 정렬 방지
# [4] 전역 예외 처리
@app.errorhandler(Exception)
def error_handling(error):
MyDB.disconnect() # 데이터베이스 접속 해제
return {
'message': "".join(error.args),
'timestamp': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}, 500
# =================================================================
# [5-3] 데이터 삭제 API > where 절에 사용할 pk 값을 path 파라미터로 정의
@app.route("/departments/<id>",methods=["DELETE"])
def delete(id):
conn=MyDB.connect()
#참조키를 고려하여 데이터 삭제구문 준비
sql1 = text("""DELETE FROM enrollments
WHERE subject_id IN (SELECT id FROM subjects WHERE department_id=:id)
OR student_id IN (SELECT id FROM students WHERE department_id=:id)""")
sql2 = text("DELETE FROM subjects WHERE department_id=:id")
sql3 = text("DELETE FROM students WHERE department_id=:id")
sql4 = text("DELETE FROM professors WHERE department_id=:id")
sql5 = text("DELETE FROM departments WHERE id=:id")
params = {"id": id}
conn.execute(sql1, params)
conn.execute(sql2, params)
conn.execute(sql3, params)
conn.execute(sql4, params)
conn.execute(sql5, params)
conn.commit() #변경 사항을 데이터 베이스에 영구 저장
MyDB.disconnect()
return {"timestamp": dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
# =================================================================
# [6] Flask 웹 서버 가동
if __name__ == "__main__":
app.run(host='127.0.0.1', port=9091, debug=True)
자식키가 지워지지 않으면 부모키를 못지운다
따라서 참조 관계를 거슬러 올라가면서 하나씩 다 지워야함

삭제의 경우 출력할 값이 없으므로 처리 시각만 표시된다
'빅데이터 국비 교육' 카테고리의 다른 글
| [아이티윌 빅데이터 52기] Python Basic | 데이터 베이스에 CSV 파일 넣기 | 파이썬에서 SQL 로 데이터 추출하기 (0) | 2025.10.31 |
|---|---|
| [아이티윌 빅데이터 52기] LAB 09 | Python Basic | 데이터 베이스 프로그래밍 (0) | 2025.10.30 |
| [아이티윌 빅데이터 52기] Day 14 Python Basic | 메일링 리스트 (0) | 2025.10.29 |
| [아이티윌 빅데이터 52기] Day 13 Python Basic | 모듈과 라이브러리 / 파이썬 내장 라이브러리 (0) | 2025.10.29 |
| [아이티윌 빅데이터 52기] Day 12 Python Basic | 객체지향 프로그래밍의 이해 (0) | 2025.10.22 |