[Flask-②] 파이썬 Flask 라우팅, 요청/응답 처리와 템플릿 렌더링
파이썬 Flask 라우팅, 요청/응답 처리와 템플릿 렌더링
웹 개발,
단순히 URL에 반응하는 것만으로는 부족하죠.
동적으로 데이터를 받고, 응답을 처리하고,
아름다운 화면까지 보여줘야 진짜 웹 애플리케이션입니다!
안녕하세요 여러분!
Flask의 기초를 잡은 첫날에 이어, 오늘은 Flask 라우팅의 심화와 HTTP 요청 및 응답 처리, 그리고 템플릿 렌더링까지 실전 웹 개발에 필요한 핵심 기능들을 배우는 시간을 가져보려고 해요.
특히 Jinja2 템플릿을 활용한 동적 페이지 구현은 처음 보면 살짝 낯설 수 있지만, 익숙해지면 정말 강력한 도구가 된답니다.
또한 클라이언트로부터 전달받는 다양한 형태의 요청 데이터를 처리하는 방법,
그리고 응답의 생성과 상태 관리까지 다뤄볼 예정이에요.
오늘 내용을 잘 익히면, 여러분만의 멋진 웹 인터페이스를 만들 수 있는 기본기를 탄탄히 다질 수 있을 거예요 😊
목차
1. Flask 라우팅 심화 🌐
1-1. 동적 경로와 변수
Flask의 가장 강력한 기능 중 하나는 라우트에서 동적 경로를 쉽게 처리할 수 있다는 점이에요.
예를 들어 블로그 글을 클릭했을 때 /posts/3
처럼 글 번호를 URL에 포함시키고 싶을 때가 있죠?
그럴 때는 이렇게 작성해요:
@app.route('/posts/<int:post_id>')
def show_post(post_id):
return f"Post ID: {post_id}"
여기서 <int:post_id>
는 URL의 일부분을 정수형 변수로 받아와서 파이썬 함수의 인자로 넘기는 역할을 해요.
string
, float
, path
같은 변환기도 사용할 수 있답니다.
1-2. HTTP 메서드 라우팅
기본적으로 Flask의 라우트는 GET 요청만 처리해요.
그런데 데이터 저장이나 수정이 필요할 때는 POST, PUT, DELETE 같은 메서드를 써야 하겠죠?
@app.route('/submit', methods=['GET', 'POST'])
def submit():
if request.method == 'POST':
return 'Form submitted!'
return 'Submit your form.'
이렇게 methods
인자를 사용하면 GET과 POST를 모두 처리할 수 있어요.
사용자 입력을 받는 폼이나 API를 만들 때 필수적인 기능이에요!
1-3. 라우팅 우선순위와 404 처리
라우트가 여러 개 있을 경우, Flask는 위에서 아래로 읽으면서 먼저 일치하는 것을 실행해요.
그래서 더 구체적인 라우트를 먼저 정의하는 것이 좋아요.
또한 정의되지 않은 경로로 사용자가 접속하면 Flask는 기본적으로 404 Not Found 에러 페이지를 보여줘요.
이 페이지도 @app.errorhandler(404)
데코레이터로 커스터마이징할 수 있어요.
@app.errorhandler(404)
def not_found(e):
return render_template('404.html'), 404
사용자 경험을 위한 작은 배려! 에러 페이지도 예쁘게 만들어두면 좋겠죠?
- 동적 경로는
<타입:변수명>
형식으로 지정 -
methods
로 다양한 HTTP 요청 대응 - 라우트 순서가 중요! 더 구체적인 경로 먼저 정의
2. HTTP 요청과 응답 처리 📩
2-1. Request 객체 이해하기
Flask에서는 request
객체를 통해 클라이언트로부터 받은 다양한 데이터를 조회할 수 있어요.
이 객체는 flask 모듈에서 자동으로 제공되며, 전역에서 접근 가능합니다.
다음은 주요 속성들입니다:
속성 | 설명 |
---|---|
request.args |
URL 쿼리스트링 (GET 방식)의 파라미터를 딕셔너리 형태로 반환 |
request.form |
폼 데이터를 조회할 때 사용 (POST 방식) |
request.get_json() |
JSON 형식의 본문 데이터를 파싱하여 반환 (API 제작 시 유용) |
예시 코드
from flask import request
@app.route('/search')
def search():
keyword = request.args.get('q')
return f"검색어: {keyword}"
2-2. 응답 생성 및 상태코드
Flask에서는 반환값으로 문자열을 주면 자동으로 HTTP 응답이 만들어지지만,
Response
객체를 직접 생성하거나 jsonify
를 활용해 JSON 형식으로 응답을 보낼 수도 있어요.
from flask import Response, jsonify
@app.route('/custom')
def custom_response():
return Response("직접 만든 응답", status=201)
@app.route('/api/data')
def api_data():
data = {"name": "Flask", "version": 2.0}
return jsonify(data), 200
상태 코드 200
(성공), 201
(생성됨), 400
(잘못된 요청), 404
(페이지 없음), 500
(서버 에러) 등은 직접 지정할 수 있어요.
2-3. 쿠키와 세션
사용자 상태를 유지하려면 쿠키와 세션을 사용해야 해요.
Flask에서는 request.cookies
로 쿠키를 읽고, response.set_cookie
로 저장할 수 있어요.
세션은 session
객체를 사용해 딕셔너리처럼 데이터를 저장할 수 있어요.
이를 통해 로그인 상태를 유지하거나, 특정 사용자에게 맞춤 정보를 제공할 수 있죠.
from flask import session
@app.route('/set_session')
def set_session():
session['username'] = 'python_user'
return '세션 저장 완료!'
@app.route('/get_session')
def get_session():
return f"저장된 사용자: {session.get('username')}"
세션은 내부적으로 쿠키를 사용하긴 하지만, 암호화되어 안전하고 편리하게 데이터를 저장할 수 있어요.
단, 세션을 사용하려면 app.secret_key
를 설정해줘야 한답니다.
3. 템플릿 렌더링과 Jinja2 🧩
3-1. Jinja2 기본 문법
Flask는 Jinja2라는 템플릿 엔진을 기본으로 사용합니다.
Python 코드를 HTML 안에 자연스럽게 녹여서 동적인 웹페이지를 만들 수 있게 해주죠!
기본 문법은 아래와 같아요:
-
{{ 변수 }}
: 파이썬 변수 출력 -
{% if 조건 %}
,{% for 요소 in 리스트 %}
: 제어문
예시 코드 (템플릿)
<ul>
{% for user in users %}
<li>{{ user }}</li>
{% endfor %}
</ul>
3-2. render_template 사용법
템플릿 파일은 Flask 프로젝트의 templates
폴더 안에 두어야 하고, 이를 불러오려면 render_template
함수를 사용합니다.
from flask import render_template
@app.route('/hello')
def hello():
return render_template('hello.html', name='Flask')
이렇게 하면 templates/hello.html
을 찾아서 {{ name }}
부분에 'Flask'
를 출력하게 돼요.
3-3. 템플릿 상속과 레이아웃 구성
Jinja2는 템플릿 상속을 지원해서, 공통된 레이아웃을 base.html
에 작성하고 다른 템플릿에서 상속받을 수 있어요.
예를 들어:
<body>
<header><h1>My Site</h1></header>
{% block content %}{% endblock %}
</body>
{% extends "base.html" %}
{% block content %}
<p>Hello, {{ name }}!</p>
{% endblock %}
이 구조 덕분에 중복을 줄이고, 각 페이지에 필요한 콘텐츠만 작성하면 되니까 유지보수도 훨씬 쉬워지죠!
3-4. 템플릿에서 동적 콘텐츠 출력
템플릿은 단순히 정적인 HTML을 보여주는 게 아니라,
Python 쪽에서 넘긴 데이터를 받아서 동적으로 리스트를 출력하거나 조건 분기를 적용할 수도 있어요.
@app.route('/posts')
def post_list():
posts = ['첫 번째 글', '두 번째 글', '세 번째 글']
return render_template('posts.html', posts=posts)
템플릿(posts.html)에서는 아래처럼 반복문을 사용해서 출력할 수 있죠:
<ul>
{% for post in posts %}
<li>{{ post }}</li>
{% endfor %}
</ul>
정말 마법 같죠?
Flask와 Jinja2만 있으면 동적 웹 페이지를 어렵지 않게 만들 수 있답니다 ✨
4. 정적 파일 제공 🎨
4-1. static 디렉토리의 역할
웹페이지가 동작하려면 CSS, 이미지, JavaScript 같은 정적 파일이 꼭 필요하죠.
Flask에서는 static/
폴더를 통해 이 정적 리소스를 제공해요.
예를 들어
static/style.css
라는 파일이 있다면,
템플릿에서 아래처럼 불러올 수 있어요:
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
url_for('static', filename='파일명')
은 Flask에서 정적 파일의 URL을 안전하게 생성해주는 방법이에요.
경로를 직접 쓰는 것보다 이 방식이 훨씬 안전하답니다.
4-2. 정적 파일 구성 예시
프로젝트 내 디렉토리 구성 예시는 아래와 같아요:
project/
│
├── app.py
├── static/
│ ├── style.css
│ └── logo.png
└── templates/
└── index.html
템플릿 안에서 이 파일들을 다음과 같이 불러올 수 있어요:
<img src="{{ url_for('static', filename='logo.png') }}" alt="로고">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
4-3. 간단한 스타일링 실습
style.css
를 만들어 아주 간단한 배경색과 폰트를 설정해볼게요.
/* static/style.css */
body {
background-color: #f9f9f9;
font-family: 'Noto Sans KR', sans-serif;
}
h1 {
color: #1b6ca8;
}
그리고 템플릿에서 해당 CSS를 로딩하면 웹페이지에 기본 스타일이 적용돼요.
이렇게 하면 프로젝트에 디자인적인 생명이 불어넣어지죠!
TIP 💡
Bootstrap이나 Tailwind 같은 외부 CSS 프레임워크도 정적 파일로 함께 사용하거나 CDN 링크로 불러와서 템플릿에 간단히 적용할 수 있어요!
5. 라우트 및 템플릿 실습 페이지 만들기 🛠️
5-1. 여러 페이지 연결하기
Flask에서 여러 웹페이지를 만드는 방법은 정말 간단해요!
각 페이지마다 라우트와 템플릿을 하나씩 연결하면 끝입니다.
예를 들어 메인 페이지와 소개 페이지를 만들어 서로 링크로 연결해보죠.
@app.route('/')
def index():
return render_template('index.html')
@app.route('/about')
def about():
return render_template('about.html')
템플릿에서는 url_for
을 활용해서 내부 링크를 쉽게 만들 수 있어요 👇
<a href="{{ url_for('index') }}">홈으로</a>
<a href="{{ url_for('about') }}">소개 페이지</a>
5-2. 동적 데이터 출력 실습
이번에는 파이썬 리스트를 만들어 템플릿에 넘겨보고,
Jinja2의 반복문을 사용해 동적으로 내용을 출력해볼 거예요.
마치 실제 게시판처럼요!
@app.route('/posts')
def posts():
post_list = [
{'title': '첫 번째 글', 'author': '홍길동'},
{'title': '두 번째 글', 'author': '이몽룡'},
{'title': '세 번째 글', 'author': '성춘향'}
]
return render_template('posts.html', posts=post_list)
posts.html
에서는 이렇게 리스트를 테이블로 출력할 수 있어요:
<table border="1">
<tr><th>제목</th><th>작성자</th></tr>
{% for post in posts %}
<tr>
<td>{{ post.title }}</td>
<td>{{ post.author }}</td>
</tr>
{% endfor %}
</table>
5-3. 실습 마무리 및 팁
이제 여러분은 라우팅을 설정하고, HTML 템플릿을 렌더링하고, 동적 데이터를 출력하는 전 과정을 경험해보셨어요.
이걸 바탕으로 나중에는 사용자 로그인, 댓글 작성, 데이터베이스 연동 같은 고급 기능도 훨씬 수월하게 이해할 수 있어요.
항상 시작은 작게, 그러나 제대로! 지금 만든 코드들도 훌륭한 출발점이 될 수 있어요.
- 여러 라우트로 페이지 구성하기
- Jinja2 반복문으로 리스트 출력하기
- 정적 링크와 템플릿 상속으로 구조화하기
6. 폼 입력과 데이터 처리 실습 ✍️
6-1. HTML 폼 만들기
사용자의 입력을 서버에 전달하려면 폼이 필요하겠죠.
HTML에서는 <form>
태그를 사용하고, Flask는 이를 POST
방식으로 받아 처리할 수 있어요.
<form action="/contact" method="POST">
이름: <input type="text" name="name"><br>
메세지: <textarea name="message"></textarea><br>
<input type="submit" value="전송">
</form>
6-2. POST 요청 처리하기
Flask에서는 request.form
을 사용해서 사용자가 입력한 데이터를 받아올 수 있어요.
그리고 조건문으로 GET인지 POST인지 구분해서 처리하면 돼요!
@app.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'POST':
name = request.form['name']
message = request.form['message']
return render_template('result.html', name=name, message=message)
return render_template('contact.html')
result.html
에서는 이렇게 입력값을 출력할 수 있어요:
<p>{{ name }}님이 보내신 메세지입니다.</p>
<blockquote>{{ message }}</blockquote>
6-3. 폼 처리 요약과 유의점
- GET 요청은 주로 폼을 보여줄 때 사용
- POST 요청은 실제 입력 데이터를 서버로 보낼 때 사용
-
request.form
을 통해 데이터를 추출하고 응답에 활용
지금은 단순히 입력값을 받아 출력하는 수준이지만,
나중엔 이 데이터를 DB에 저장하거나 이메일로 전송할 수도 있답니다!
실습 결과 요약 📝
기능 | 설명 |
---|---|
폼 렌더링 | GET 요청 시 contact.html 렌더링 |
데이터 수신 | POST 요청 시 사용자의 입력값을 추출 |
결과 출력 | result.html에서 입력값을 표시 |
마무리 ✨
이번 시간에는 Flask의 핵심 기능 중 하나인 라우팅과 요청/응답 처리,
그리고 템플릿 렌더링까지 웹 애플리케이션을 구성하는 기본 요소들을 차근차근 살펴봤어요.
단순히 URL을 연결하는 것에서 그치지 않고, 사용자의 요청을 읽고 응답을 생성하며, 템플릿을 통해 멋진 동적 페이지까지 만들어낸 경험은 정말 인상적이었을 거예요 😊
이제 여러분은 단순한 Flask 앱이 아니라, 실제 사용자와 상호작용할 수 있는 인터페이스 중심의 웹 서비스를 만들 수 있는 준비가 되셨습니다.
아직 데이터베이스나 사용자 인증 같은 내용은 남아있지만, 오늘 배운 내용을 기반으로 앞으로의 실습도 훨씬 수월하게 진행될 거예요. 😄