Flask 활용한 웹 개발

summereuna🐥·2024년 6월 9일
0

Python

목록 보기
6/8

사용자의 요청에 맞춰 HTML 파일을 응답해주는 Flask 서버를 만들기

  • 내가 가진 컴퓨터는 한 대 뿐이지만,
    내 컴퓨터에 서버도 만들고, 요청도 해보자. 즉, 클라이언트 = 서버
  • 이런 환경을 "로컬 개발 환경"이라고 한다.

백엔드-프론트엔드를 연결하는 일이 익숙해지도록,
로또 추천 사이트 → 영화 검색 사이트 → 데일리모토 → DB 연습 → 멜로디쉐어
순서대로 개념을 충분히 다지면서 프로젝트를 진행

1. Flask 기초


1-1. 폴더 생성 및 가상 환경 설치


1-1-1. 폴더와 파일 생성


Flask는 만들 프로젝트의 폴더 구조가 정해져 있기 때문에 규칙을 지켜야 한다.

  1. 폴더 안에 app.py 파일 생성
  2. 폴더 안에 templates 폴더 생성
  3. templates 폴더 안에 index.html 파일 생성
flask 폴더 구조
- - -
flask
|— venv
|— app.py (서버)
|— templates
   |— index.html (클라이언트 파일)

📌 규칙

  • templates 폴더는 반드시 고정해야 한다.
  • 첫 페이지는 일반적으로 파일명은 index.html을 사용
  • app.py는 변경해도 되지만, 라이브러리 이름과 같은 것을 이름으로 사용하면 안된다.

1-1-2. 가상 환경 만들기


원하는 라이브러리만 설치해서 관리할 수 있도록 담아두는 공구함, 가상환경을 설치하자. 폴더에 하나씩 설치한다.

1. VSC에서 명령 팔레트 실행

  • Windows → Ctrl + Shift + P
  • macOS → Command + Shift + P

2. 명령 팔레트에서 가상 환경 생성

  1. env 검색
  2. Python : Create Environment(환경 만들기) 클릭
  3. 가상환경 선택지 중 원하는 것 선택 (난 Venv 선택함)
  4. 파이썬 버전 선택
  5. .venv 폴더 생성되면 가상 환경 생성 완료

1-2. Flask 패키지(라이브러리) 설치


터미널에서 Flask 패키지 설치

  • pip install flask

  • pip list 로 잘 설치되었는지 확인할 수 있음

1-3. Flask의 기본 폴더 구조


Flask 서버를 만들 때, 항상 프로젝트 폴더 안에 templates 폴더app.py 파일 만들고 시작한다.

프로젝트 폴더
 ㄴ/templates 폴더 (html파일 넣음)
 ㄴapp.py 파일

2. Flask 기초


Flask로 로또 추천 사이트를 만들어보자.

Flask는 프레임워크로, 서버를 구동시켜주는 편한 코드 모음이다.

  • 웹 서버를 구동하는데 필요한 복잡한 코드들을 쉽게 가져다 쓸 수 있다.
  • 프레임워크는 3분 요리/소스 세트

2-1. app.py 파일에 flask 시작 코드 작성하고 서버 연결하기


  1. app.py 파일에 flask 시작 코드 작성
from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return 'This is Home!'

if __name__ == '__main__':  
    # app.run(debug=True) # 포트 5000 이미 사용중이면 포트에 5001 넣어주자.
    app.run('0.0.0.0', port=5001, debug=True)
  1. 터미널에 python app.py 또는 python3 app.py을 입력하여 서버를 킨다.
  • 로컬 호스트 url을 클릭하면 아래 처럼 페이지가 뜨는 것을 확인할 수 있다.
  1. 서버 끄려면 Ctrl+C

2-2. URL에 따라 다른 화면 보여주기


2-2-1. @app.route('/')

@app.route('/') 부분을 수정하면 URL을 나눌 수 있다.

  • url 별로route('/')내의 주소가 달라야 한다.

2-2-1. def 함수명()

  • url 별로 함수명도 달라야 한다.
from flask import Flask
app = Flask(__name__)

# ✅ / 홈 url 설정
@app.route('/')        # 🔥 루트 주소
def home():            # 🔥 함수명
   return 'This is Home!'

# ✅ /mypage url 설정
@app.route('/mypage')  # 🔥 루트 주소
def mypage():          # 🔥 함수명
   return 'This is My Page!'

if __name__ == '__main__':  
   app.run(debug=True)
  • 로컬호스트:5001/mypage

2-3. templates 폴더의 역할: HTML 파일 불러오기


templates 폴더는 HTML 파일을 담아두고, 불러오는 역할을 한다.

1. templates 폴더에 html 생성하기

/templates/index.html 파일 생성하기

2. html 파일 불러오기: render_template("index.html")

app.py에서 flask 내장함수인 render_template("index.html")를 이용하여 HTML 파일을 불러올 수 있다.
프레임워크의 위력! 간단!

# 🔥 render_template 임포트
from flask import Flask, render_template 
app = Flask(__name__)

@app.route('/')
def home():
    # 🔥 render_template() 사용하여 html 파일 불러오고 return
    return render_template('index.html') 

@app.route('/mypage')
def mypage():
    return 'This is my page!'

if __name__ == '__main__':  
    app.run('0.0.0.0', port=5001, debug=True)

2-4. HTML 파일에 데이터 넘겨주기


보통 홈페이지에서는 데이터에 따라서 값이 변하는 경우가 많다.
서버에서 사용자가 보게 될 웹 페이지로 데이터를 넘겨주는 방법을 알아보자.

2-4-1. render_template("index.html", 데이터이름=데이터)

1. app.py에서 html로 데이터 넘겨주기

데이터를 넘겨주려면 변수에 원하는 데이터를 넣고, render_template('index.html', 데이터이름=데이터) 방식으로 코드를 추가하면 된다.

@app.route('/')
def home():
    # 🔥 name 변수에 데이터 담기
    name = "예티"
    
    # render_template 사용하여 html 파일 불러온 것 반환하기
    # 🔥 data에 name 데이터 넣어 보내기
    return render_template('index.html', data=name) 

2. index.html에서 받은 데이터 사용하기

그러면 HTML에서 정해둔 데이터 이름(지금은 data)로 Python 서버의 데이터를 사용할 수 있다.

<!DOCTYPE html>
<html lang="kor">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
  </head>
  <body>
    <h1>안녕하세요, {{data}}님!</h1>
  </body>
</html>

2-4-2. 데이터 여러개 dict에 담아 넘겨주기


1. 딕셔너리에 여러 변수를 담아 보내면 된다.

# 딕셔너리에 여러 변수 담기
context = {
	"HTML에서 사용할 이름": 변수명,
	"HTML에서 사용할 이름": 변수명,
}
@app.route('/')
def home():
    # 🔥 변수에 데이터 담기
    name = "예티"
    lotto = [5, 7, 13, 20, 28, 36]

    # 🔥 여러 데이터 넘겨주기 위해 딕셔너리에 담기
    context = {
        "name": name,
        "lotto": lotto,
    }

    # render_template 사용하여 html 파일 불러온 것 반환하기
    # 🔥 data에 context 딕셔너리 넣어 보내기
    return render_template("index.html", data=context) 

2. index.html에서 data를 받는다.

<!DOCTYPE html>
<html lang="kor">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
  </head>
  <body>
    <h1>안녕하세요, {{ data.name }}님!</h1>
    <h2>로또 번호: {{ data.lotto }}</h2>
  </body>
</html>

2-5. html 파일에서 반복문 사용하기


1. 리스트의 요소를 하나씩 출력해 주자.

📝 html 반복문 숏 컷

ffor: 반복문

{% for element in collection %}
	{{ element|e }}
{% endfor %}
    <h1>안녕하세요, {{ data.name }}님!</h1>
    <h2>로또 번호: {{ data.lotto }}</h2>
    {% for number in data.lotto %}
    		{{ number }}
    {% endfor %}
  </body>

2. 반복문과 HTML 태그를 함께 사용할 수도 있다.

  • ol 태그는 ordered list의 약자로 숫자나 알파벳 같은 마커를 붙여 놓는다.
  <body>
    <h1>안녕하세요, {{ data.name }}님!</h1>
    <h2>로또 번호: {{ data.lotto }}</h2>
    <ol>
      {% for number in data.lotto %}
      <li>{{ number }}</li>
      {% endfor %}
    </ol>
  </body>

(예제) 로또 당첨 갯수 계산하기:html에서 조건문 사용하기


실제 로또처럼 자동으로 번호를 뽑아서 등수를 계산해주는 프로그램을 만들어 보자.

1. 로또 번호 6개 출력하는 함수 만들기

로또는 무작위로 1~45까지 숫자 6개를 중복해서 뽑아야 한다.

import random # 🔥 random 메서드 임포트

# 🔥 1~46 까지 숫자 중, 6개의 로또 번호 랜덤하게 골라와 list로 반환하는 함수
def generate_lotto_numbers():
    numbers = random.sample(range(1, 46), 6)
    return sorted(numbers)

# 🔥 함수 호출하여 반환 된 값(6개 랜덤 숫자를 가진 list)을
# 🔥 lotto_numbers 변수에 담기
lotto_numbers = generate_lotto_numbers()

print("추출된 로또 번호:", lotto_numbers)

2. app.py에 코드 작성

from flask import Flask, render_template
import random # 🔥 랜덤 메소드

app = Flask(__name__)

@app.route('/')
def home():
    # name 변수에 데이터 담기
    name = "예티"
    lotto = [5, 7, 13, 20, 28, 36]

    # 🔥 1~46 까지 숫자 중, 6개의 로또 번호 랜덤하게 골라와 list로 반환하는 함수
    def generate_lotto_numbers():
        numbers = random.sample(range(1, 46), 6)
        return sorted(numbers)
    
    # 🔥 함수 호출하여 반환 된 값(6개 랜덤 숫자를 가진 list)을
    # 🔥 lotto_numbers 변수에 담기
    lotto_numbers = generate_lotto_numbers()
    print("추출된 로또 번호:", lotto_numbers)

    # 여러 데이터 넘겨주기 위해 딕셔너리에 담기
    context = {
        "name": name,
        "lotto": lotto,
        "random_lotto": lotto_numbers,
    }
    
# ...

3. index.html에서 랜덤 로또 번호 받기

data.키이름 으로 데이터를 가져온다. 헷갈리지 말자~

  <body>
    <h1>안녕하세요, {{ data.name }}님!</h1>
    <h2>로또 번호: {{ data.lotto }}</h2>
    <ol>
      {% for number in data.lotto %}
      <li>{{ number }}</li>
      {% endfor %}
    </ol>
    <h2>랜덤 로또 번호: {{ data.random_lotto }}</h2>
  </body>

2-6. html 파일에서 조건문 사용하기


(예제) 로또 당첨 확인 기능: set(list) & set(list) 교집합 사용


1. 파이썬 리스트 2개에서 같은 요소의 갯수를 확인하는 함수 만들기

집합 자료형 특징: set()

  • 특징
    • 중복을 허용하지 않는다.
    • 순서가 없다(Unordered).

  • set은 중복을 허용하지 않는 특징 때문에
    데이터의 중복을 제거하기 위한 필터로 종종 사용된다.
  • 리스트나 튜플은 순서가 있기(ordered) 때문에 인덱싱을 통해 요솟값을 얻을 수 있지만, set 자료형은 순서가 없기(unordered) 때문에 인덱싱을 통해 요솟값을 얻을 수 없다.
    • 이는 마치 딕셔너리와 비슷하다. 딕셔너리 역시 순서가 없는 자료형이므로 인덱싱을 지원하지 않는다.
  • 만약 set 자료형에 저장된 값을 인덱싱으로 접근하려면 리스트나 튜플로 변환한 후에 해야 한다.

set() 메서드로 교집합 구하기

&를 이용하면 교집합을 간단히 구할 수 있다.

s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])
print(s1 & s2) # [4, 5, 6]
def count_common_elements(list1, list2):
	# set() 메서드: 집합 자료형 만들기
    common_elements = set(list1) & set(list2)
    
    # len() 메서드: list의 length 구하기
    return len(common_elements)    

# 예시 리스트
list1 = [1, 2, 3, 4, 9]
list2 = [4, 5, 6, 7, 8]

common_count = count_common_elements(list1, list2)
print("두 리스트에서 공통된 요소의 개수:", common_count)

2. app.py에 함수 넣기

from flask import Flask, render_template
import random # 🔥 랜덤 메소드

app = Flask(__name__)

@app.route('/')
def home():
    # name 변수에 데이터 담기
    name = "예티"
    lotto = [5, 7, 13, 20, 28, 36]

    # ✅ 랜덤 숫자 함수
    # 1~46 까지 숫자 중, 6개의 로또 번호 랜덤하게 골라와 list로 반환하는 함수
    def generate_lotto_numbers():
        numbers = random.sample(range(1, 46), 6)
        return sorted(numbers)
    
    # 함수 호출하여 반환 된 값(6개 랜덤 숫자를 가진 list)을 lotto_numbers 변수에 담기
    lotto_numbers = generate_lotto_numbers()
    # print("추출된 로또 번호:", lotto_numbers)


    # ✅ 로또 당첨 확인 함수
    def count_common_elements(list1, list2):
        # set() 메서드: 집합 자료형 만들기
        common_elements = set(list1) & set(list2)
        # len() 메서드: list의 length 구하기
        return len(common_elements)
    
    # 내가 고른 lotto 숫자 list, 랜덤 로또 숫자 리스트 인자로 보내고 
    # 반환된 교집합 리스트를 common_count 변수에 할당
    common_count = count_common_elements(lotto, lotto_numbers)
    # print("두 리스트에서 공통된 요소의 개수:", common_count)


    # 여러 데이터 넘겨주기 위해 딕셔너리에 담기
    context = {
        "name": name,
        "lotto": lotto,
        "random_lotto": lotto_numbers,
        "common_count": common_count,
    }

    # render_template 사용하여 html 파일 불러온 것 반환하기
    # data에 name 데이터 넣어 보내기
    return render_template("index.html", data=context) 

@app.route('/mypage')
def mypage():
    return 'This is my page!'

if __name__ == '__main__':  
    app.run('0.0.0.0', port=5001, debug=True)

3. html 조건문 작성하기

📝 html 조건문 숏 컷

fif: if 조건문

{% if expression %}
	blockofcode
{% endif %}

fife: if else 조건문

{% if expression %}
	blockofcode
{% else %}
	blockofcode
{% endif %}

felif: if elif else 조건문

{% if expression %}
    blockofcode
{% elif expression2 %}
    blockofcode
{% else %}
    blockofcode
{% endif %}
<body>
    <h1>안녕하세요, {{ data.name }}님!</h1>
    <h2>로또 번호: {{ data.lotto }}</h2>
    <ol>
      {% for number in data.lotto %}
      <li>{{ number }}</li>
      {% endfor %}
    </ol>
    <h2>랜덤 로또 번호: {{ data.random_lotto }}</h2>

    {% if data.common_count == 6 %}
    <h2>{{ data.common_count }}개 맞았습니다! 로또 1등입니다.</h2>
    {% elif data.common_count == 5 %}
    <h2>{{ data.common_count }}개 맞았습니다! 로또 2등입니다.</h2>
    {% elif data.common_count == 4 %}
    <h2>{{ data.common_count }}개 맞았습니다! 로또 3등입니다.</h2>
    {% elif data.common_count == 3 %}
    <h2>{{ data.common_count }}개 맞았습니다! 로또 4등입니다.</h2>
    {% else %}
    <h2>💥{{ data.common_count }}개 맞았습니다! 탈락!💥</h2>
    {% endif %}
  </body>

css 적용하기


로또 홈페이지를 만들려고 하는데, HTML로 공 6개 있는 홈페이지 코드를 작성해보자.

1. 공 모양 css 작성

<style>
  .ball {
  display: inline-block;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: #FFD700;
  color: #FFFFFF;
  text-align: center;
  line-height: 30px;
  margin-right: 5px;
  }
  
  .ball--random {
  display: inline-block;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: red;
  color: #FFFFFF;
  text-align: center;
  line-height: 30px;
  margin-right: 5px;
  }
</style>

2. index.html에 적용

<h2>로또 번호</h2>
{% for number in data.lotto %}
<div class="ball">{{ number | e}}</div>
{% endfor %}

<h2>랜덤 로또 번호</h2>
{% for number in data.random_lotto %}
<div class="ball--random">{{ number | e}}</div>
{% endfor %}

3. 이미지 넣기

  • /static/image 폴더를 만든다.
  • image 폴더에 원하는 이미지 파일을 넣는다.

이미지 태그는 url_for 사용

  • url_for는 보통 경로(위치)를 표현할 수 있다.
  • 이미지 경로 부분을 바꾸면 된다.
<img src="{{ url_for('static', filename='이미지 경로') }}" alt="캐릭터 이미지" />
<style>
  .img{
  	height: 100px;
  }
</style>

<div>
  <img class="img" src="{{ url_for('static', filename='image/pochacco.png') }}" alt="캐릭터 이미지" />
</div>

연습: 영화 검색 사이트 만들기


1. movie 페이지 보여주기


/movie 경로로 접속하면 movie.html 페이지를 보여주도록 코드를 작성

  • app.py에 페이지 루트 작성 및 템플릿 연결
@app.route('/movie')
def movie():
    return render_template('movie.html')
  • /templates/movie.html 생성
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>영화 검색</h1>
</body>
</html>

2. 검색 기능 만들기


사용자로부터 입력(데이터)를 받아서 처리하기

  1. form 만들기
    form 은 회원 가입, 검색, 게시글 작성에 사용
    form 에 데이터를 입력하고 전송 버튼을 누르면, 입력한 데이터가 서버로 전송된다.
    • action 에는 url_for 로 데이터를 보낼 url을 설정한다.
    • name 속성을 활용해서 데이터에 명찰을 붙인다.
  2. movie.html
<form action="{{ url_for('movie') }}"> //데이터를 보낼 곳
  <input type="text" name="query"> //데이터 이름 지정
  <button type="submit">검색</button>
</form>
  1. form에서 보내준 검색어를 받기
    movie 함수에서 request.args.get('name 속성명')를 활용하면 Form에서 입력한 데이터를 받을 수 있다.
  • app.py
from flask import Flask, render_template, request # request 라이브러리로 데이터 요청

@app.route('/movie')
def movie():
    print(request.args.get('query')) # 🔥 Form에서 입력한 데이터를 받기
    return render_template('movie.html')

3. 영화 검색 기능 구현


영화 검색 기능은 영화 진흥원 API를 활용하기

영화진흥위원회 API 코드 사용하기

res = requests.get(
	"http://kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json?key=f5eef3421c602c6cb7ea224104795888"
)
rjson = res.json()
movie_list = rjson["movieListResult"]["movieList"]

영화진흥위원회 API로 영화 데이터 받아오기

영화진흥위원회 API는 GET 방식으로 호출한다.

  • GET 방식이란 주소에 키=값 형식으로 데이터를 넣어서 요청하는 방식
    • 예를 들면 구글 검색에서 파이썬을 검색하면
      https://www.google.com/search?q=파이썬 형태로 주소값이 변경된다.

영화진흥위원회 API 데이터 확인하기

기생충을 검색하고 싶다면, 기존 주소 끝에 &movieNm=기생충 을 붙이면 된다.

4. 검색 데이터 받아오기


영화진흥위원회 API에서 응답으로 준 데이터 구조를 파악하면서 작성하자..

  • pip install requests 설치하기

  • app.py 작성

from flask import Flask, render_template, request
import random # 🔥 랜덤 메소드
import requests # 🔥 pip로 설치

@app.route("/movie")
def movie():
	# 🔥 사용자가 입력한 검색어 받기
    query = request.args.get('query') 
    
    # 🔥 사용자 입력 값인 query를 영화진흥원 api에 넣어 영화명으로 검색  
    # 🔥 URL 앞에 f 붙여야 {변수} 넣어 쓸 수 있다.
    URL = f"http://kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json?key=f5eef3421c602c6cb7ea224104795888&movieNm={query}" 
    
    # 🔥 requests.get() 메서드로 응답 get
    res = requests.get(URL)
    rjson = res.json()
    
    # 🔥 데이터 넣기
    movie_list = rjson["movieListResult"]["movieList"]
    
    # 🔥 movie_list를 data에 넣어 "movie.html"로 보내기
    return render_template("movie.html", data=movie_list)

5. 결과 html 에 출력


<body>
  <h1>영화 검색</h1>
  <form action="{{ url_for('movie') }}">
    <input type="text" name="query">
    <button type="submit">검색</button>
  </form>
  {% for movie in data %}
      <!-- <p>{{ movie }}</p> -->
      <p>영화 제목: {{ movie.movieNm }}</p>
      <p>타입: {{ movie.typeNm }}</p>
      {% if movie.directors %}
        <p>감독: {{ movie.directors[0].get('peopleNm') }}</p>
      {% endif %}
      <hr>
  {% endfor %}

</body>
  • 아이언맨 검색한 결과
profile
Always have hope🍀 & constant passion🔥

0개의 댓글