๐Ÿผ ๋ฐฑ์•ค๋“œ/Flask

Flask ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ์กฐ์™€ ๋™์ž‘ ์›๋ฆฌ

๊ณ„๋ž€์†Œ๋…„ 2025. 3. 26. 17:34

๋ฐฑ์•ค๋“œ

 

๋ฐฑ์—”๋“œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ ‘๊ทผํ•˜์ง€ ์•Š๋Š” ์„œ๋ฒ„ ์ธก ์‹œ์Šคํ…œ์„ ์˜๋ฏธํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ์ธ์ฆ, API ์ œ๊ณต ๋“ฑ์„ ๋‹ด๋‹นํ•œ๋‹ค.

๋ฐฑ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ๋ž€?

  • ๋ฐฑ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋„๊ตฌ ๋ชจ์Œ์ด๋‹ค.
  • ๊ฐœ๋ฐœ์ž๋Š” ์ด๋ฅผ ํ†ตํ•ด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ณด์•ˆ ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ก ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ ์ 

  • โœ… ๋ฐ˜๋ณต์ ์ธ ์ž‘์—… ๊ฐ์†Œ → ์š”์ฒญ ๋ผ์šฐํŒ…, ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ ๋“ฑ์„ ์ž๋™ํ™”
  • โœ… ๊ฐœ๋ฐœ ์†๋„ ํ–ฅ์ƒ → ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋จ
  • โœ… ๋””๋ฒ„๊น…๊ณผ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ์ œ๊ณต → ์˜ค๋ฅ˜ ์ฐพ๊ธฐ๊ฐ€ ์‰ฌ์›€

์–ด๋–ค ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ณ ๋ฅผ์ง€ ๊ณ ๋ ค์‚ฌํ•ญ

  • ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ์™€ ๋ณต์žก๋„
  • ํ”„๋ ˆ์ž„์›Œํฌ ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ
  • ์ปค๋ฎค๋‹ˆํ‹ฐ
  • ๋ผ์ด์„ ์Šค ์ •์ฑ…

Flask

  • ์žฅ์ 
    • ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ€๋ณ๋‹ค. ๋ถˆํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด ์—†์–ด, ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • ์ž์œ ๋„๊ฐ€ ๋†’๋‹ค. ๊ฐ•์ œ์ ์ธ ๊ตฌ์กฐ ์—†์ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • ๋‹จ์ 
    • ๋ณต์žกํ•œ ๊ฐœ๋ฐœ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ธฐ๋ณธ ์ œ๊ณต ๊ธฐ๋Šฅ์ด ์ ์–ด์„œ, ํฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์„ค์ •ํ•  ๊ฒŒ ๋งŽ์•„์ง

 

๋ฐฑ์•ค๋“œ๋ฅผ ์œ„ํ•œ ๋””์ž์ธ ํŒจํ„ด

 

๋””์ž์ธํŒจํ„ด: ์†Œํ”„ํŠธ์›จ์–ด ์„ค๊ณ„์—์„œ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ•œ ์—ฌ๋Ÿฌ ๋””์ž์ธ ํŒจํ„ด์ด ์‚ฌ์šฉ

MVCํŒจํ„ด: Model - View - controller

  • ๋ชจ๋ธ: ๋ฐ์ดํ„ฐ์™€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ด€๋ฆฌ
  • ๋ทฐ: ๋ ˆ์ด์•„์›ƒ๊ณผ ํ™”๋ฉด ์ฒ˜๋ฆฌ
  • ์ปจํŠธ๋กค๋Ÿฌ: ๋ช…๋ น์„ ๋ชจ๋ธ๊ณผ ๋ทฐ ๋ถ€๋ถ„์œผ๋กœ ๋ผ์šฐํŒ…

ํ”Œ๋ผ์Šคํฌ MVC ๊ตฌ์กฐ

  • Model: ORM์‚ฌ์šฉํ•œ DB๊ตฌ์กฐ
  • View: Jinja ํ…œํ”Œ๋ฆฟ
  • Controller: @app.route()๋กœ ์ •์˜๋œ ํ•จ์ˆ˜๋“ค
project/
โ”‚
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ models/       ← Model (SQLAlchemy ๋ชจ๋ธ ๋“ฑ)
โ”‚   โ”œโ”€โ”€ views/        ← View (Jinja ํ…œํ”Œ๋ฆฟ)
โ”‚   โ”œโ”€โ”€ controllers/  ← Controller (Flask route ํ•จ์ˆ˜๋“ค)
โ”‚   โ”œโ”€โ”€ static/       ← ์ •์  ํŒŒ์ผ (CSS, JS ๋“ฑ)
โ”‚   โ””โ”€โ”€ __init__.py   ← ์•ฑ ํŒฉํ† ๋ฆฌ. ๋น„์–ด์žˆ๋Š” ํŒŒ์ผ. ์ž‘์„ฑํ•ด๋„ ๋˜๊ณ  ์•ˆํ•ด๋„ ๋จ.
โ”‚
โ”œโ”€โ”€ config.py
โ””โ”€โ”€ run.py

 

์›น ์„œ๋ฒ„, WAS, WSGI 

 

์›น ์„œ๋ฒ„ (Web Server): ์ •์  ํŒŒ์ผ์„ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„

  • ๋Œ€ํ‘œ์ ์ธ ์›น ์„œ๋ฒ„: Nginx, Apache
  • HTML, CSS, JavaScript ๊ฐ™์€ ์ •์ ์ธ ํŒŒ์ผ์„ ์ œ๊ณตํ•˜๋Š” ์—ญํ• 
  • ํ•˜์ง€๋งŒ Flask/Django ๊ฐ™์€ ๋™์  ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ง์ ‘ ์‹คํ–‰ํ•˜์ง€ ๋ชปํ•จ
  • ๊ทธ๋ž˜์„œ ๋™์  ์š”์ฒญ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด WAS๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

WAS (Web Application Server): ๋™์  ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„

  • (Java ํ™˜๊ฒฝ): Tomcat, JBoss, WebLogic
  • (Python ํ™˜๊ฒฝ): Gunicorn, uWSGI (WSGI ์„œ๋ฒ„)
  • ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์„ ๋ฐ›์•„์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ณ , DB ์กฐํšŒ ํ›„ ์‘๋‹ต์„ ์ƒ์„ฑ
  • WAS๊ฐ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹น

 

WSGI(Web Server Gateway Interface)

  • ํŒŒ์ด์ฌ์—์„œ ์›น ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค, ์›น์„œ๋ฒ„์™€ ํŒŒ์ด์ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•œ ๊ทœ์•ฝ
    • ์ธํ„ฐํŽ˜์ด์Šค: ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์ด๋‚˜ ํ”„๋กœ๊ทธ๋žจ์ด ๊ณตํ†ต๋œ ํ˜•์‹์œผ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •ํ•œ ๊ทœ์น™
    • REST API์—์„œ JSON ํ˜•์‹์œผ๋กœ ์š”์ฒญ์„ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ฒƒ → ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์ด ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ์ธํ„ฐํŽ˜์ด์Šค
  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์˜ˆ: Flask, Django ๋“ฑ)๊ณผ ์›น ์„œ๋ฒ„(์˜ˆ: Gunicorn, uWSGI, Nginx)๋Š” ์„œ๋กœ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š”๋ฐ, ์ด ๋‘˜์ด ์„œ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค‘๊ฐ„์—์„œ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๊ทœ์•ฝ์ด WSGI
    • WAS(์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„) = ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„
    • ํŒŒ์ด์ฌ์—์„œ๋Š” WAS ๋Œ€์‹  WSGI ์„œ๋ฒ„(Gunicorn, uWSGI ๋“ฑ)๋ฅผ ์‚ฌ์šฉ
  • Nginx, Apache์™€ ๊ฐ™์€ ์„œ๋ฒ„๋“ค์€ django, flask๋กœ ์ž‘์„ฑํ•œ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•œ๋‹ค.
  • ์ด ๋•Œ WSGI๋ฅผ ์ด์šฉํ•ด ์›น ์„œ๋ฒ„์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์„œ๋กœ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ

 

Java ํ™˜๊ฒฝ

  • ์›น ์„œ๋ฒ„: Nginx, Apache
  • WAS: Tomcat, JBoss
  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: Spring Boot, JSP

Python ํ™˜๊ฒฝ

  • ์›น ์„œ๋ฒ„: Nginx, Apache
  • WSGI ์„œ๋ฒ„ (WAS ์—ญํ• ): Gunicorn, uWSGI
  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜: Flask, Django, Fast API

 

WSGI ์„œ๋ฒ„๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹

์„œ๋ฒ„ ๊ตฌ์„ฑ: Nginx + Gunicorn + Flask

  1. ์‚ฌ์šฉ์ž๊ฐ€ http://example.com์— ์ ‘์†
  2. Nginx๊ฐ€ ์š”์ฒญ์„ ๋ฐ›์Œ → ์ •์  ํŒŒ์ผ์ด๋ฉด ์ง์ ‘ ์‘๋‹ต
  3. ์ •์  ํŒŒ์ผ์ด ์•„๋‹ˆ๋ผ๋ฉด ์š”์ฒญ์„ Gunicorn(WSGI ์„œ๋ฒ„)์œผ๋กœ ์ „๋‹ฌ
  4. Gunicorn์ด Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ
  5. Flask๊ฐ€ DB ์กฐํšŒ ๋“ฑ ์ฒ˜๋ฆฌ ํ›„ ์‘๋‹ต์„ Gunicorn์— ๋ฐ˜ํ™˜
  6. Gunicorn์ด ์‘๋‹ต์„ Nginx์— ์ „๋‹ฌ
  7. Nginx๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €)์—๊ฒŒ ์‘๋‹ต

๐Ÿ‘‰ Nginx๋Š” ์ •์  ํŒŒ์ผ ์ฒ˜๋ฆฌ, Gunicorn์€ ๋™์  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” WAS ์—ญํ• 

 

 

Flask

 

ํŒŒ์ด์ฌ ๊ฐ€์ƒํ™˜๊ฒฝ ์ƒ์„ฑ

# pip๋กœ ์ตœ์ดˆ ๊ฐ€์ƒํ™˜๊ฒฝ ์ƒ์„ฑ
python -m venv myvenv

# ๊ฐ€์ƒํ™˜๊ฒฝ ํ™œ์„ฑํ™”
source myvenv/bin/activate

# ๊ฐ€์ƒํ™˜๊ฒฝ ๋น„ํ™œ์„ฑํ™”
deactivate

 

๊ฐ€์ƒํ™˜๊ฒฝ์—์„œ ํ”Œ๋ผ์Šคํฌ ์„ค์น˜

# pip ์—…๊ทธ๋ ˆ์ด๋“œ
$ python -m pip install --upgrade pip

# flask ์„ค์น˜
$ pip install flask

# ํ”Œ๋ผ์Šคํฌ๋Š” app.py๋ฅผ ์‹œ์ž‘ํŒŒ์ผ๋กœ ์ธ์‹ํ•˜์—ฌ ์‹คํ–‰์ด ์‹œ์ž‘ 
$ flask run

# flask run --debug ๋ช…๋ น์„ ์‹คํ–‰ํ•ด ๋””๋ฒ„๊น…์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •
$ flask run --debug

 

python app.py vs flask run

 

  • python app.py
    • Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹
    • if name == "main": app.run() ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ํŒŒ์ผ์„ ์ง์ ‘ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋ฉฐ, Flask์˜ ๊ธฐ๋ณธ ๋‚ด์žฅ ์„œ๋ฒ„๊ฐ€ ๊ตฌ๋™๋œ๋‹ค.
    • ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ํ™œ์„ฑํ™”: app.run(debug=True)๋ฅผ ์ฝ”๋“œ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
  • flask run
    • Flask์˜ CLI๋ฅผ ์ด์šฉํ•ด ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
    • FLASK_APP ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋ฉฐ, CLI์—์„œ ๋‹ค์–‘ํ•œ ์„ค์ •์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ํ™œ์„ฑํ™”: flask run์€ ์‹คํ–‰ํ•  ๋•Œ flask run --debug ์˜ต์…˜์„ ๋ถ™์ด๋ฉด ๋˜๋ฉฐ
      • .flaskenv ๊ฐ™์€ ํ™˜๊ฒฝ ํŒŒ์ผ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด, ๋ณด๋‹ค ํ™•์žฅ์„ฑ์ด ๋†’๊ณ  ์‹ค๋ฌด์—์„œ ์„ ํ˜ธ๋œ๋‹ค.
  • ๊ฒฐ๋ก ์ ์œผ๋กœ, python app.py๋Š” ์ž‘์€ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ„๋‹จํžˆ ์‹คํ–‰ํ•  ๋•Œ ์ ํ•ฉํ•˜๊ณ , flask run์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • ๋ฐ ๋‹ค์–‘ํ•œ ์˜ต์…˜์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋” ์œ ์—ฐํ•œ ๋ฐฉ์‹์ด๋‹ค.
  • ๋‚˜๋Š” ํ•ญ์ƒ ์žฅ๊ณ ๋‚˜ fast api ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ flask run ์„ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด๋‹ค.

 

# test.py - ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” app.py ๋ผ๋Š” ํŒŒ์ผ์„ ์‹œ์ž‘์ ์œผ๋กœ ํ•ด์„œ ๋‚˜๋จธ์ง€ ํŒŒ์ผ์„ ์ฝ๋Š”๋‹ค.

from flask import Flask

# Flask ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ
# ์ด ํŒŒ์ผ์— ๋‹ค๋ฅธ ํŒŒ์ผ ๊ฒฝ์œ  ์—†์ด test.py๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋œ๋‹ค๋ฉด __name__ ๋ณ€์ˆ˜์—๋Š” 'test'๋ผ๋Š” ๋ฌธ์ž์—ด์ด ๋‹ด๊น€
app = Flask(__name__)

# URL๊ณผ FLASK์ฝ”๋“œ๋ฅผ ๋งคํ•‘ํ•˜๋Š” Flask ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
@app.route('/')
def hello():
    return 'Hello'


if __name__ == '__main__':
    app.run()
  • python test.py๋กœ ์‹คํ–‰ํ•˜๋ฉด name ๊ฐ’์ด 'main'์ด ๋˜์–ด app.run()์ด ์‹คํ–‰๋œ๋‹ค. ์ฆ‰, Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ง์ ‘ ์‹คํ–‰๋œ๋‹ค.
  • flask run์„ ์‹คํ–‰ํ•˜๋ฉด Flask๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ app.py๋ฅผ ์ฐพ์ง€๋งŒ, ๋งŒ์•ฝ ํŒŒ์ผ๋ช…์ด test.py๋ผ๋ฉด?
    • Flask๋Š” test.py๋ฅผ ๋ชจ๋ฆ„โŒ
    • FLASK_APP=test.py ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋ฉด test.py๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋งฅ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋  ๋•Œ FLASK_APP ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ์‹œ์ž‘ ํŒŒ์ผ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ .zshrc ํŒŒ์ผ์—์„œ export FLASK_APP=test.py๋ฅผ ์„ค์ •ํ•˜๋ฉด, flask run ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ test.pyํŒŒ์ผ์ด ์‹œ์ž‘์ ์œผ๋กœ ์‹คํ–‰

 

Flask ๊ตฌ์กฐ

 

flask๋‚˜ django๋‚˜ fast-api๋‚˜ ๋˜‘๊ฐ™๋‹ค.

  • models.py
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์—ญํ• 
    • Flask์—์„œ๋Š” ORM์„ ์ง€์›ํ•˜๋Š” ํŒŒ์ด์ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋„๊ตฌ์ธ SQLAlchemy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋ชจ๋ธ์„ ์ •์˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…, ์ˆ˜์ •, ์‚ญ์ œ ๋ฐ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋‹ด๋‹น
  • forms.py
    • ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์„œ๋ฒ„๋กœ ์ „์†ก๋œ ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ
    • Flask์—์„œ๋Š” WTForms๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํผ์„ ๋ชจ๋ธ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌ
    • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ์„œ๋ฒ„๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ํผ์„ ์ •์˜
  • templates ๋””๋ ‰ํ„ฐ๋ฆฌ
    • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” HTML ํŒŒ์ผ์ด ์ €์žฅ
    • Flask์—์„œ๋Š” Jinja2 ํ…œํ”Œ๋ฆฟ ์—”์ง„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ ์ธ ์ฝ˜ํ…์ธ ๋ฅผ HTML ํŒŒ์ผ์— ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.
  • views ๋””๋ ‰ํ„ฐ๋ฆฌ
    • ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋“ค๋กœ ๊ตฌ์„ฑ๋œ ๋ทฐ ํŒŒ์ผ๋“ค์ด ์ €์žฅ
    • ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ๋Šฅ์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ทฐ ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
    • ๊ฐ ๋ทฐ ํŒŒ์ผ์—๋Š” URL ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๋‹ด๊ฒจ ์žˆ๊ณ  ํ•ด๋‹น ๊ฒฝ๋กœ์— ๋Œ€ํ•œ HTML์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  • static ๋””๋ ‰ํ„ฐ๋ฆฌ
    • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ •์  ํŒŒ์ผ(CSS ํŒŒ์ผ, JavaScript ํŒŒ์ผ, ์ด๋ฏธ์ง€ ํŒŒ์ผ)๋“ค์„ ์ €์žฅ
    • ์ •์  ํŒŒ์ผ์€ ์›น ํŽ˜์ด์ง€์˜ ์Šคํƒ€์ผ์ด๋‚˜ ๋™์ž‘์„ ์ œ์–ดํ•˜๋ฉฐ ํ•œ๋ฒˆ ์—…๋กœ๋“œ๋œ ํ›„์—๋Š” ์ˆ˜์ •๋˜์ง€ ์•Š๊ณ  ๊ณ ์ •
  • config.py
    • config.py ํŒŒ์ผ์€ ํ”„๋กœ์ ํŠธ์˜ ์„ค์ •์„ ๊ด€๋ฆฌ
    • ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์ •๋ณด ๋“ฑ ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์— ๊ฑธ์นœ ์„ค์ •์„ ๊ธฐ๋ก
    • ex) ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค URI, ๋น„๋ฐ€ ํ‚ค, ํ™˜๊ฒฝ ์„ค์ • ๋“ฑ์„ ์ด ํŒŒ์ผ์—์„œ ์ •์˜ํ•˜๊ณ , Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋  ๋•Œ ์ด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์„ค์ •์„ ์ ์šฉ

 

Blueprint

  • ๋ฌธ์ œ ์ƒํ™ฉ

create_appํ•จ์ˆ˜ ์•ˆ์— ์ƒˆ๋กœ์šด URL ๋งคํ•‘์ด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๋ผ์šฐํŒ… ํ•จ์ˆ˜๋“ค์„ ๊ณ„์† ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด, create_appํ•จ์ˆ˜๋Š” ์ ์  ๊ธธ๊ณ  ๋ณต์žกํ•ด์ง„๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง์— ๋”ฐ๋ผ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์ง€๊ณ , ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

  • Blueprint์˜ ์—ญํ• 

Blueprint๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ๋ชจ๋“ˆ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ ๋ชจ๋“ˆ์€ ์ž์ฒด์ ์œผ๋กœ ๋ผ์šฐํŒ…, ๋ทฐ ํ•จ์ˆ˜, ํ…œํ”Œ๋ฆฟ ๋“ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ , ๋‚˜์ค‘์— ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ†ตํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ด๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ธฐ๋Šฅ๋ณ„๋กœ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Blueprint์˜ ํŠน์ง•
  1. ๊ธฐ๋Šฅ๋ณ„ ๋ถ„๋ฆฌ
    • Blueprint๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ธฐ๋Šฅ๋ณ„๋กœ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, "ํšŒ์›๊ฐ€์ž…", "๊ฒŒ์‹œํŒ", "๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€" ๋“ฑ์œผ๋กœ ๋‚˜๋ˆ ์„œ ๊ฐ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ผ์šฐํŒ…๊ณผ ๋ทฐ ํ•จ์ˆ˜๋“ค์„ ๋ณ„๋„์˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ™•์žฅ์„ฑ ํ–ฅ์ƒ
    • ๊ฐ Blueprint๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ธฐ์กด์˜ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • ํ•œ ๋ฒˆ ๋งŒ๋“  Blueprint๋Š” ๋‹ค๋ฅธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  4. ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด
    • ๊ฐ ๊ธฐ๋Šฅ์„ ๋ณ„๋„์˜ ๋ชจ๋“ˆ๋กœ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด์ œ Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Blueprint๋ฅผ ํ™œ์šฉํ•œ ๋ผ์šฐํŒ… ๋ชจ๋“ˆํ™”ํ•ด๋ณด์ž

myproject/
โ”‚
โ”œโ”€โ”€ blueprints/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ product.py
โ”‚   โ””โ”€โ”€ user.py
โ”‚
โ””โ”€โ”€ app.py

 

 

blueprints/product.py

from flask import Blueprint, jsonify

# Blueprint ์ƒ์„ฑ (์ด๋ฆ„: product_bp, URL ํ”„๋ฆฌํ”ฝ์Šค: /product)
product_bp = Blueprint('product', __name__, url_prefix='/product')

@product_bp.route('/list')
def product_list():
    return jsonify({"message": "Product List Page"})

@product_bp.route('/detail/<int:product_id>')
def product_detail(product_id):
    return jsonify({"message": f"Product Detail for ID {product_id}"})
  • ์ œํ’ˆ๊ณผ ๊ด€๋ จ๋œ ๋ผ์šฐํŠธ๋ฅผ ๊ด€๋ฆฌ 
  • ex) ์ œํ’ˆ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€์™€ ๊ฐœ๋ณ„ ์ œํ’ˆ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณต
  • product_bp๋Š” /product URL ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ๊ฐ€์ง„ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ 
  • /product/list์™€ /product/detail/<int:product_id> URL์— ๋Œ€ํ•œ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌ

 

blueprints/user.py

from flask import Blueprint, jsonify

# Blueprint ์ƒ์„ฑ (์ด๋ฆ„: user_bp, URL ํ”„๋ฆฌํ”ฝ์Šค: /user)
user_bp = Blueprint('user', __name__, url_prefix='/user')

@user_bp.route('/profile')
def profile():
    return jsonify({"message": "User Profile Page"})

@user_bp.route('/settings')
def settings():
    return jsonify({"message": "User Settings Page"})
  • ์‚ฌ์šฉ์ž์™€ ๊ด€๋ จ๋œ ๋ผ์šฐํŠธ๋ฅผ ๊ด€๋ฆฌ, ์‚ฌ์šฉ์ž ํ”„๋กœํ•„๊ณผ ์„ค์ •์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณต
  • user_bp๋Š” /user URL ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ๊ฐ€์ง„ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ 
  • /user/profile์™€ /user/settings URL์— ๋Œ€ํ•œ ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌ

 

 Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— Blueprint ๋“ฑ๋ก

from flask import Flask

from blueprints.product import product_bp
from blueprints.user import user_bp

# Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ
app = Flask(__name__)

# Blueprint ๋“ฑ๋ก (user_bp์™€ product_bp)
app.register_blueprint(user_bp)
app.register_blueprint(product_bp)

@app.route('/')
def hello():
    return 'Hello'


if __name__ == '__main__':
    app.run()

์ด์ œ app.py ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๊ฐ Blueprint๋ฅผ Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋“ฑ๋กํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ฐ Blueprint์—์„œ ์ •์˜ํ•œ URL ๋ผ์šฐํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

  • app.py์—์„œ user_bp์™€ product_bp๋ฅผ ์ž„ํฌํŠธํ•˜์—ฌ Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋“ฑ๋ก
  • @app.route('/')๋Š” ๊ธฐ๋ณธ ํŽ˜์ด์ง€. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋˜๋ฉด 'Hello'๋ฅผ ์ถœ๋ ฅ

์‹คํ–‰ ๊ฒฐ๊ณผ

์ด์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋ฉด, ๊ฐ Blueprint์—์„œ ์ •์˜ํ•œ URL ๋ผ์šฐํŠธ์— ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • /product/list: ์ œํ’ˆ ๋ชฉ๋ก ํŽ˜์ด์ง€
  • /product/detail/<int:product_id>: ํŠน์ • ์ œํ’ˆ ์„ธ๋ถ€ ์ •๋ณด ํŽ˜์ด์ง€
  • /user/profile: ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ํŽ˜์ด์ง€
  • /user/settings: ์‚ฌ์šฉ์ž ์„ค์ • ํŽ˜์ด์ง€

 

ํŒฉํ† ๋ฆฌ ํŒจํ„ด

 

Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ ๋ฐฉ๋ฒ•

from flask import Flask

app = Flask(__name__)

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

if __name__ == '__main__':
    app.run()

์ด ๋ฐฉ์‹์˜ ๋‹จ์ 

  • ์•ฑ์ด ํ•˜๋‚˜์˜ ๊ณ ์ •๋œ ์ธ์Šคํ„ด์Šค(app)์— ์ข…์†๋จ
  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ, ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ, ์šด์˜ ํ™˜๊ฒฝ๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•˜๋ ค๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง
  • ์•ฑ์„ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ํ™•์žฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ๋”ฐ๋กœ ๋“ฑ๋กํ•ด์•ผ ํ•จ

 

ํŒฉํ† ๋ฆฌ ํŒจํ„ด

from flask import Flask

def create_app():
    app = Flask(__name__)
    
    # ์„ค์ • ์ ์šฉ
    app.config.from_object('config')

    # ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ๋“ฑ๋ก (์˜ˆ: auth ๊ด€๋ จ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ)
    from app.blueprints.auth.routes import auth_bp
    app.register_blueprint(auth_bp)

    return app

์ด ๋ฐฉ์‹์˜ ์žฅ์ 

  1. ํ™˜๊ฒฝ๋ณ„ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ
  2. Blueprint์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๋ชจ๋“ˆํ™”ํ•˜๊ธฐ ์‰ฌ์›€
  3. ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์šฉ์ด

 

๊ฐœ๋ฐœ/์šด์˜ ํ™˜๊ฒฝ ์„ค์ •์„ ์‰ฝ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ

import os

def create_app():
    app = Flask(__name__)

    # ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ๋”ฐ๋ผ ์„ค์ • ํŒŒ์ผ ๋‹ค๋ฅด๊ฒŒ ๋กœ๋“œ
    env = os.getenv('FLASK_ENV', 'development')
    
    if env == 'development':
        app.config.from_object('config.DevConfig')
    elif env == 'production':
        app.config.from_object('config.ProdConfig')

    return app