플라스크 프레임워크

파이썬으로 작성된 마이크로 웹 프레임워크이다.
이 프레임워크를 통해 웹페이지 제작이 가능하며,
Reddit, Linkedin, Netflix, Uber, Zillow, Airbnb 와 같은 사이트들이 플라스크를 이용해 개발되었다.

마이크로 웹 프레임워크 :
특별한 도구 또는 라이브러리가 필요 없는 프레임워크



다른 프레임워크와 비교

프레임워크 언어 설명
flask python 작성하기 비교적 간단하다. MVC를 명확하게 분리해 사용하지 않아도 되지만, 다른 프레임워크보다 적은 기능들만 구현이 가능하다. 프로그래밍 언어 특성상 많은 접속자를 감당할 수 없다. 또한, 사이트가 복잡해질수록 체계적인 관리가 어렵다는 단점이 있다.
Django python 모델-뷰-컨트롤러가 분리된 MVC 모델을 짜는 데 최적화되어있다. 프로그래밍 언어 특성상 많은 접속자를 감당할 수 없다.
Java를 이용한 서버 java 많은 접속자를 감당할 수 있으며, 현업에 필요한 보안 기능 등을 구현할 수 있다. 또한 위 두 프레임워크보다 많은 기능을 구현할 수 있으며, 현업에서 많이 사용되는 만큼 그 정보 또한 더 쉽게 얻을 수 있다. MVC모델을 명확히 구분해 구축할 수 있다.



준비

  • flask 설치
1
pip install flask



사용법

플라스크는 컨트롤러와 모델이 하나의 코드파일에서 작성이 가능하다.

시작하기

(1) flask를 import 해준다.
(2) 변수에 flask 를 선언해준 뒤, 이 변수에 페이지들을 쌓아준다.
(3) 새로운 페이지는 메서드 정의 형태 (def)로 선언한다.
(4) 데코레이터(@)로 페이지에 접속하는 요청 경로를 선언한다.
(5) 플라스크 서버 실행은 변수명.run 을 통해 해주며, 호스트와 포트넘버 지정이 이 때 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app = Flask(__name__)

@app.route("/")
def anyname():
    return "안녕하세요 아무개입니다."

@app.route('/app1')
def app1():
    return 'hello, its app1'
    
@app.route('/app2')
def app2():
    return 'hello, its app2'

# app.run(host = '192.168.10.25', port = 5000)
app.run(host = 'localhost', port = 5002)

HTML 코드 사용

HTML 코드를 string화 하여 return에 넘겨줌으로써 html 코드 사용이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import Flask

app = Flask(__name__)    

@app.route('/')
def anyname():
    page = f'''
    <html>
    <head><title> 아무개입니다. </title></head>
    <body>
    <p>안녕하세요. 아무개입니다.</p>
    </body>
    </html>
    '''
    return page

app.run(host = 'localhost', port = 5002)

동적 변수 사용

동적 변수는 html코드 내 중괄호 {동적변수} 로 선언하여 사용할 수 있다.
아래는, 페이지에 방문할 때마다 방문 횟수가 1씩 증가하는 페이지를 만드는 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from flask import Flask

app = Flask(__name__)    
mycount = 0

@app.route('/')
def anyname():
    global mycount
    mycount += 1
    page = f'''
    <html>
    <body>
    <p>{mycount}회 방문입니다.</p>
    </body>
    </html>
    '''
    return page

app.run(host = 'localhost', port = 5002)

여러 페이지 만들고 연결하기

여러 페이지를 만들고, 서로 이동을 하는 구조 또한 만들 수 있다.
아래 예시에서는 아래와 같은 총 3개의 페이지를 가지고 있다.

(1) build_input_page : 방문횟수가 표시되는 페이지
(2) app_input : 방문횟수를 +1 씩 카운트하는 페이지
(3) root : 처음 방문하면 보이는 루트 페이지. app_input으로 연결되는 링크를 가지고 있다.

그리고 이들 페이지는 아래와 같이 연결된다.

No 페이지 작동 내용 행위
1     root로 접속
2 root root페이지가 표시됨 root페이지의 링크 클릭
3 input count에 +1이 더해짐  
4 build_input_page build_input페이지가 표시됨  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from flask import Flask

app = Flask(__name__)    
mycount = 0

def build_input_page(my_count):
    page = f'''
    <html>
    <body>
    <p>안녕하세요. 아무개입니다.</p>
    <p>{mycount}회 방문입니다.</p>
    </body>
    </html>
    '''
    return page

@app.route('/input')
def app_input():
    global mycount
    mycount += 1
    page = build_input_page(mycount)
    return page

@app.route('/')
def root():
    return'''
    <html>
    <body>
    <a href='/input'> 이 곳을 누르면 방문 횟수로 count 됩니다. </a>
    </body>
    </html>
    '''

app.run(host = 'localhost', port = 5002)

상호작용 페이지 만들기 = 요청 받기

Flask의 request 모듈을 이용하여, 페이지 접속자의 요청값을 받아올 수 있다.

요청값을 받는 방법은 (1)주소창을 통해 요청값을 받을 수 있고, (2)아래와 같이 입력 form을 이용할 수도 있다.

1
2
3
4
<form action='입력 요청값을 보낼 페이지' method='get'>
입력해주세요 : <input type='text' name='입력값 변수 명'></input>
<input type='submit'></input>
</form>

받은 요청값을 이용하는 페이지의 데코레이터에는 아래와 같이 methods 를 지정해주면 됩니다.

1
@app.route('요청명', methods=['POST', 'GET'])

받은 요청값을 백엔드부에서 이용하기 위해, 아래와 같이 백엔드 변수에 받은 요청값을 넣어줄 수 있다.

1
백엔드 변수명 = request.args.get('입력값 변수명')

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from flask import Flask
from flask import request
# 수신 결과를 받는 모듈 flask.request

app = Flask(__name__)

def build_input_page():
    page = f'''
    <html>
    <body>
    Iris 분류를 위해 꽃의 치수를 cm 단위로 입력해 주세요. <br>
    
    <form action='http://localhost:5002/result' method='get'>
    sepal_length : <input type='text' name='sepal_length'></input>cm<br>
    sepal_width : <input type='text' name='sepal_width'></input>cm<br>
    petal_length : <input type='text' name='petal_length'></input>cm<br>
    petal_width : <input type='text' name='petal_width'></input>cm<br>
    <input type='submit'></input><br>
    </form>
    
    </body>
    </html>
    '''
    return page

def build_result_page():
    
    sepal_length = request.args.get('sepal_length')
    sepal_width = request.args.get('sepal_width')
    petal_length = request.args.get('petal_length')
    petal_width = request.args.get('petal_width')
    
    multiple = (int(sepal_length) * int(sepal_width) * int(petal_length) * int(petal_width))
    # multiple = sepal_length * sepal_width * petal_length * petal_width

    page = f'''
    수신 내용이 맞는지 확인해주세요 <br>
    * sepal_length : {sepal_length} <br>
    * sepal_width : {sepal_width} <br>
    * petal_length : {petal_length} <br>
    * petal_width : {petal_width} <br>

    모든 값 곱하기 : {multiple}<br>
    '''
    return page

@app.route('/')
def home_page():
    page = build_input_page()
    return page

@app.route('/result', methods=['POST','GET'])
def result_page():
    page = build_result_page()
    return page

app.run(host='localhost', port=5002)

분류 모델을 불러와 이용해보기

미리 학습된 Iris 분류용 DecisionTree 모델 dt_model 을 불러와, 사용자의 요청값에 따라 꽃의 종류를 분류해주는 페이지를 작성해본다.

사용자 요청값을 받아오고 이용하는 방법은 윗 단락 (상호작용 페이지 만들기 = 요청 받기) 을 확인하면 된다.

미리 학습된 모델은 피클로 저장되었으며, 아래와 같은 코드로 불러와 사용한다.

1
2
with open('pickled_model_iris.bin', 'rb') as f:
    dt_model_loaded = pickle.load(f)

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from flask import Flask
from flask import request
import pickle

app = Flask(__name__)

# 모델 불러오기
with open('pickled_model_iris.bin', 'rb') as f:
    dt_model_loaded = pickle.load(f)
    
# 꽃 종류 이름들
label_names = ['setosa', 'versicolor', 'virginica']

def build_input_page():
    page = f'''
    <html>
    <body>
    Iris 분류를 위해 꽃의 치수를 cm 단위로 입력해 주세요. <br>
    
    <form action='http://localhost:5002/result' method='get'>
    sepal_length : <input type='text' name='sepal_length'></input>cm<br>
    sepal_width : <input type='text' name='sepal_width'></input>cm<br>
    petal_length : <input type='text' name='petal_length'></input>cm<br>
    petal_width : <input type='text' name='petal_width'></input>cm<br>
    <input type='submit'></input><br>
    </form>
    
    </body>
    </html>
    '''
    return page

def build_result_page():
    
    sl = float(request.args.get('sepal_length'))
    sw = float(request.args.get('sepal_width'))
    pl = float(request.args.get('petal_length'))
    pw = float(request.args.get('petal_width'))
    
    global dt_model_loaded
    global label_names
    
    result_idx = dt_model_loaded.predict([[sl, sw, pl, pw]])
    result_name = label_names[int(result_idx)]

    page = f'''
    수신 내용이 맞는지 확인해주세요 <br>
    * sepal_length : {sl} <br>
    * sepal_width : {sw} <br>
    * petal_length : {pl} <br>
    * petal_width : {pw} <br>
    * 꽃의 종류 : {result_name}<br>
    '''
    return page

@app.route('/')
def home_page():
    page = build_input_page()
    return page

@app.route('/result', methods=['POST','GET'])
def result_page():
    page = build_result_page()
    return page

app.run(host='localhost', port=5002)



백엔드 - 프론트엔드 분리

파이썬 프레임워크에서는 ‘템플릿’이라고 부르는 프론트엔드 코드를 외부에 빼 따로 개발을 진행할 수 있다. (뷰와 컨트롤러의 분리가 목적이다.)
템플릿은 html과 같은 뷰를 만들 수 있는 코드가 해당된다.
더불어 CSS와 같은 외부 스타일시트도 사용이 가능하다.

  • 템플릿들은 templates 폴더 안에 위치해야 한다.
  • CSS 파일은 static 폴더 안에 위채해야 한다.
  • 이미지, 멀티미디어 소스 등 또한 static 폴더 안에 위치해야 한다.

백엔드(컨트롤러) - 프론트엔드 분리

플라스크에서 템플릿 파일을 이용하기 위해 flask 라이브러리 내의 render_template 모듈을 사용한다.

1
2
3
4
5
6
7
8
9
10
11
# 백엔드 코드 
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/')
def home_page():
    return render_template("flask_index.html")

app.run(host = 'localhost', port = 5002)
1
2
3
4
5
6
7
8
<!-- 뷰(html) 코드 -->
<html>
    <head> 템플릿 페이지입니다. </head>
    <body> 
        안녕하세요. 템플릿 바디입니다. <br>
        render_template를 이용한 뷰 - 컨트롤 분리입니다.  <br>
    </body>
</html>

동적 변수 할당

뷰단에서 컨트롤러로부터 받은 변수를 사용할 수도 있다.
이 방식은 Django에서도 동일하다.

먼저, 컨트롤러에서 뷰로 전달할 변수를 render_template 메서드의 파라미터 값으로 선언을 해주고,

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/')
def home_page():
    page = render_template("flask_index.html",
                           var1 = '변수 1입니다.',
                           var2 = '변수 2입니다.')
    return page

app.run(host = 'localhost', port = 5002)

뷰에서는 중괄호 두 개 사이에 컨트롤러로부터 받은 변수명을 적어주는 방식으로 표현하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head> 템플릿 페이지입니다. </head>

<body>
안녕하세요. 템플릿 바디입니다. <br>
render_template를 이용한 뷰 - 컨트롤 분리입니다.  <br>

변수 선언은 아래와 같이 가능합니다.  <br>
변수1 :  <br>
변수2 : 
<body>
</html>

CSS 사용하기

뷰단에서는 미리 정의된 스타일 내용을 담고 있는 CSS파일을 불러와 사용이 가능하다.

뷰단에서 link href 태그를 이용해 사용하는 방법을 아래에 설명한다.

CSS 파일을 사용하지 않고 직접 코딩

1
2
3
4
5
6
7
8
9
10
<html>
<head>
    <style>
        body{background-color: #dddddd;}
    </style>
</head>
<body>
밝은 회색 스타일. 뷰에서 직접 스타일을 지정했습니다.  
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/')
def home_page():
    page = render_template('flask_index.html')
    return page

app.run(host = 'localhost', port = 5002)

CSS 파일을 사용해 코딩

1
2
3
4
5
6
7
8
9
<html>
<head>
    <link rel='stylesheet'
    href=''>
</head>
<body>
하늘색 스타일. CSS를 통해 스타일을 지정했습니다.
</body>
</html>
1
body{background-color: #01dddd;}
1
2
3
4
5
6
7
8
9
10
11
from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/')
def home_page():
    page = render_template('flask_index.html')
    return page

app.run(host = 'localhost', port = 5002)



마치면서

플라스크는 작성법이 간단하나, 확연한 MVC 분리에는 적합하지 않으며, 이에 따라 페이지가 많아지거나 그 구조가 복잡해질수록 체계적인 관리가 어려워진다.

이에 더불어 커버할 수 있는 동시접속자수가 자바 서버에 비해 턱없이 적은 점과, 보안 기능이 제공되지 않는다는 점에 있어서 불특정 다수 를 대상으로 하는 웹 제작에는 어울리지 않는다.

하지만 반대로, 보안 걱정이 필요 없는 폐쇄망 내에서 관리자 몇 명만을 대상으로 하는 서비스라면 간단하게 플라스크로 제작하는 것도 괜찮을 수 있다. 이 때는 오히려 다양한 기능이 필요 없을 수도 있으므로, 간단히 제작하는 플라스크가 어울릴 수 있다.

즉, 어떤 프레임워크를 이용하는지는 그 상황에 따라 달라질 수 있으며, 어떠한 게 더 낫다고 단정짓기는 힘들다.

하지만 앞서 말한 듯, 대외적인 서비스에서는 자바가 필수적이므로, 자바 공부는 꼭 필요한 것이라는 생각과 함께 이번 글을 마친다.



reference