Python

Python - Flask 활용

2020. 5. 29. 16:35

Python - Flask

Flask

  • 파이썬 기반 마이크로 웹 개발 프레임워크

  • 웹 개발의 핵심기능만 간경하게 유지

  • 필요한 기능은 다른 라이브러리나 프레임워크로 손쉽게 확장

  • 신속하게 최소한의 노력으로 웹 애플리케이션 개발 가능

Flask 특징

  • 개발용 서버와 디버거 내장

  • RESTful 요청 처리

  • Jinja2 템플릿 엔진 내장(JADE 등 다른 템플릿 엔진 사용 가능)

  • 유니코드 기반

홈페이지

개발 환경 설정

파이썬 3 설치 (파이썬 2도 가능)

가상 파이썬 실행 환경 구성 (virtualenv)

  • 다양한 환경이나 특정 실행 환경 구성하기

  • virtualev 라는 가상의 파이썬 실행 환경 지원 함

# 설치
pip install virtualenv
# 확인
virtualenv -help 
virtualenv --viersion
  • 가상 환경으로 만들고 싶은 폴더에서 명령어 실행

virtualenv venv
  • 가상 환경 활성화

cd venv/scripts
activate.bat
  • pyenv, autoenv 함께 사용하면 더 편리

플라스크 설치

pip install flask

note: could not find a version that satisfies the requirement flask가 나올 경우, 네트워크 문제로 외부 라이브러리 저장소에 접근하지 못할 경우 나오는 문제.

직접 https://github.com/mitsuhiko/flask 위치로 가서 소스 받아 설치 해야 함.

  • 설치 방법 – python setup.py install

통합개발환경(IDE) / 에디터 설치

시작하기

Hello world

  • 소스를 실행하고, terminal 에서 'python flask_test.py' 입력 후 http://127.0.0.1:5000 으로 접근

실행결과

플라스크 애플리케이션 실행 순서

  1. 특정 URL 호출(request) : http://127.0.0.1:5000/ 또는 http://localhost:5000

  2. 특정 URL 매핑 검색 : @app.route('/')

  3. 특정 URL에 매칭된 함수(def 함수) 실행 : def hello_world()

  4. 비즈니스 로직 실행 : result

  5. 결과 응답으로 전송(response): return result

  6. HTML 로 화면에 출력

  7. 쿠키(Cookie), 세션(Session), 로깅(logging) 등 제공

라우팅

  • URL을 통해 처리할 핸들러를 찾는 것

  • 플라스크는 복잡한 URI를 함수로 연결하는 방법을 제공

  • URI 를 연결하는 route() 데코레이터 함수 제공

  • / 접속 시 root_world() 가 호출 됨

  • /hello 접속 시 hello_world() 가 호출 됨

 

/hello 결과

  • 동적 변수를 사용하여 URI 접속

  • <동적변수> 를 뷰 함수의 인자로 사용

  • <동적변수> 다음에 / 를 넣으면 안됨

  • app.debug는 개발의 편의를 위해 존재

    • True값을 경우 코드를 변경하면 자동으로 서버가 재 실행 됨

    • 또한, 웹상에서 파이썬 코드를 수행할 수 있게 되므로, 운영환경에서 사용을 유의해야 함.

  • 현재 접근은 개발 소스가 존재하는 로컬에서만 접근 가능

    • 외부에서도 접근을 가능하게 하려면 app.run(host='0.0.0.0')로 서버 실행 부를 변경해야 함.

  • url_for() 함수 : 함수를 호출 하는 URI 를 반환

  • redirect() : 다른 route 경로 이동 (다른 페이지로 이동)

guest 테스트 결과

Flask GET 방식으로 값 전송 및 처리

  • mkdir templates 폴더 생성

  • login_form_get.html 파일 작성

  • get 방식 지정 : method="get"

templates폴더 및 login_form_get.html 작성

  • from flask import Flask, request, session, render_template 추가

  • 사용자가 요청한 값은 request 모듈의 args 객체의 get 메소드로 값을 가져옴

  • 내부에 methods 항목을 통해 받을 REST Action Type을 지정

@app.route('/login_get_proc', methods=['GET'])
  • 지정 이외의 Action Type을 사용하면 Flask가 405 에러를 출력

  • request 모듈에서 GET 한 파라미터 값을 가져오기 위해서는

request.args.get('name') # url?name=value name 값

app.py 작성
Get 방식 실행 결과

Flask POST 방식으로 으로 값 전송 및 처리

  • login_form_post.html 파일 작성

  • post 방식 지정 : method="post"

login_form_post.html 작성

  • 사용자가 요청한 값은 request 모듈의 form 객체로 값을 가져옴

  • 내부에 methods 항목을 통해 받을 REST Action Type을 지정

@app.route('/login_post_proc', methods=['POST'])
  • 지정 이외의 Action Type을 사용하면 Flask가 405 에러를 출력

  • request 모듈에서 POST 한 파라미터 값을 가져오기 위해서는

request.form['name'] # html form input등의 Element들의 name 값
  • request.form['name']로 사용 시 name 파라미터가 없으면 Flask가 400 에러를 출력

app.py에 post부분 추가
/login_form_post로 접속
결과

Flask 에서 HTML 처리 하기

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
   html = "<html><body><h1>Hello World</h1></body></html>"
   return html

if __name__ == '__main__':
   app.run(debug = True)
  • user_id 값 html 과 함께 처리 하기

  • 처리할 값이 많아지면 너무 복잡해 짐

@app.route('/users/<userid>') # route 데코레이터
def user_id(userid): # View 함수

    html = "<html><body><h1> User Id : "
    html = html + userid
    html = html + "</h1></body></html>"

    return html

Flask – Jinja2 템플릿 : 기본

  • 플라스크에서는 Jinja2 템플릿의 사용

  • Jinja2에 대한 더 자세한 내용은 Jinja2 Template Documentation 공식 문서를 참고

  • Jinja2 Template Documentation

  • template 폴더 생성 (Jinja2 템플릿 기본 문서 위치)

  • template 폴더 아래에 userid_view.html 생성

  • return render_template('userid_view.html', userid=userid) userid 전달

  • {{ userid }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1> User Id : {{ userid }}</h1>
</body>
</html>
@app.route('/users/<userid>') # route 데코레이터
def user_id(userid): # View 함수

    return render_template('userid_view.html', userid=userid)

Flask – Jinja2 템플릿 : 리스트(list) , 튜블(tuple) 등 전달

@app.route('/plays')
def palys():
    games = ('갤러그', '너구리', '리니지')
    sports = ['야구', '축구', '농구']
    return render_template('plays/play.html', title='PLAYS', games=games, sports=sports, )
  • play.html

  • {# 주석(comment) #}

  • 반복문 : {% for i in sports %} ~ {% endfor %}

plays 폴더 생성 후 play.html 작성

Flask – Jinja2 템플릿 : <form> 값 전달

  • input.html

templates 폴더에 input.html 작성

  • result.html

plays 폴더 안에 result.html 작성

  • flask_test.py작성

flask_test.py 작성

 

/input_form
Submit 한 result

Flask – 쿠키 (Cookie)

  • http 프로토콜은 기본적으로 상태 값을 유지 하지 않음(stateless protocol)

  • 쿠키(cookie) 와 세션(session)은 서버와 클라이언트 간 상태 값을 저장 하는 기술

  • 쿠키(cokkie) 심기 : response 객체의 set_cookie() 메서드 사용

  • 쿠키(cokkie) 일기 : request 객체의 cookie.get() 사용

app2.py 작성
templates/cookie/setcookie.html 작성
templates/cookie/readcookie.html 작성

 

http://127.0.0.1:5000 접속

 

Login 버튼 눌러서 이동된 화면

 

GET Cookie 누른 결과 창

Flask 로그인 및 세션 생성

  • 쿠키(cookie)는 클라이언트 피씨에 생성

  • 세선은 서버 메모리에 생성되어 생성 후 바로 사용 가능

app.py 작성

app.secret_key #  세션 키를 생성하며, 로그인과 같이 세션을 맺는 경우 필수적으로 넣어야 한다.
  • 세션 생성 시, app.secret_key로 키를 생성하지 않으면 Flask가 500 에러를 출력

login_form.html 작성

  • session_view.html ( 세션이 유지 되는 시간동안 세션값은 바로 사용 가능)

session_view.html 작성
/login_form
/login_proc

sqlite3 db 및 table생성

  • DB 서버 필요 없는 파일 기반 Embedded SQL DB 엔진

  • sqlite브라우저 : http://sqlitebrowser.org/

  • db 없을 시 python.db 자동 생성 됨

db_proc.py 작성
데이터베이스 열기 - python.db 클릭
Table확인

로그인 체크 로직 변경

app.py의 로그인 체크 로직 변경

  • main.html 작성

main.html

로그인 정보 수정

app.py에 내용 추가
app.py에 내용 추가

  • user_info.html

user_info.html 작성

로그아웃

  • redirect()를 활용하면, 사용자의 조회 위치를 변경할 수 있다.

  • url_for()는 route 주소로 이동하는 것이 아닌 정의된 함수를 호출한다. 위 예제에서 main을 호출하는 대상은 main()인 함수다.

  • session.clear()를 사용하면 따로 설정 필요없이 session을 비울 수 있다.

Flask 리스트 페이징 하기(list paging)

lists.html
list.html

  • Flask 소스 : miniboard_app.py
from flask import Flask, request, session, render_template, url_for
import sqlite3, math
app = Flask(__name__)

@app.route('/')
def index():
    return 'root - index'

def select():
    conn = sqlite3.connect('python.db')
    cursor = conn.cursor()
    sql = 'select * from miniboard order by idx desc'
    cursor.execute(sql)
    rows = cursor.fetchall()
    conn.close()
    return rows

def select_page(list_limit, page):
    conn = sqlite3.connect('python.db')
    cursor = conn.cursor()
    offset = (page - 1) * list_limit
    sql = 'select * from miniboard order by idx desc limit ? offset ?'
    cursor.execute(sql, (list_limit, offset))
    rows = cursor.fetchall()
    conn.close()
    return rows

def select_count():
    conn = sqlite3.connect('python.db')
    cursor = conn.cursor()
    sql = 'select count(idx) from miniboard' # 10
    cursor.execute(sql)
    rows = cursor.fetchone() # class tuple
    cursor.close()
    conn.close()
    return rows[0]

def list_test():
    list = select()
    print(list)

@app.route('/lists')
def lists():
    lists = select()
    return render_template('miniboard/lists.html', lists=lists)

@app.route('/list/<int:page>')
def list(page):
    list_num = 4
    list_count = select_count()
    #page_count = int(list_count / list_num)
    page_count = math.ceil(list_count / list_num)
    lists = select_page(list_num, page)
    return render_template('miniboard/list.html', lists=lists, page_count=page_count)

if __name__ == '__main__':
    app.secret_key = '202006011522'
    app.run(debug=True)
    #list_test()

결과창 확인

출처 : http://thecoding.kr/category/phython/phython-flask/