2015년 6월 10일 수요일

Flask - Quickstart 요약

- 가장 간단한 웹앱을 만들어 보자.

# hello.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

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


위와 같이 입력하고 command line에서 아래와 같이 입력한다.
> python hello.py

브라우저에서 http://127.0.0.1:5000에 접속하면 'Hello World!'를 볼 수 있다.

접속 URL을 컴퓨터의 ip로 바꾸고 싶으면 app.run부분을 아래와 같이 바꾸면 된다.

=> app.run(host='0.0.0.0')

디버그 모드를 키고 싶으면 아래와 같이 한다.

=> app.run(debug=True)

'/'의 요청시 hello_world() 함수가 호출되는 것은 @app.route에 의해 이루어진다.

위에서처럼 고정된 URL이 아닌 필요에 따라 변하는 URL의 경우 매칭시키고 싶으면 아래와 같이 하면 URL에서 <username> 부분이 함수의 username 파라메터로 넘어온다.

@app.route('/<username>')
def show_user_profile(username):
    return 'User %s' % username

들어오는 값을 아래와 같이 변환해 줄 수도 있다.

@app.route('/<int:post_id>')
def show_post(post_id):
    return 'Post %d' % post_id

변환해주는 값에는 아래의 3가지가 있다.
int : 정수로 변환
float: 실수로 변환
path: 마지막 '/'도 포함하는 path

- routing rule

* 마지막에 '/'가 있는 경우:
예) '/projects/'
'/projects'로 요청하면 flask는 '/projects/'로 redirect한다.

* 마지막에 '/'가 없는 경우:
예) '/projects'
'/projects/'로 요청하면 없는 페이지로 에러 발생

지금까지는 url을 함수로 매핑시켜주는 @app.route를 살펴봤다. 반대도 가능할까? url_for()를 사용하면 된다. 첫번째 파라메터는 함수의 이름이고 두번째부터는 URL에서의 변경부분이다. 없는 두번째 파라메터는 query parameter가 된다.

url_for('hello_world') => /
url_for('username', username='soo') => /username/soo
url_for('username', query='soo') => /username?query=soo

- HTTP method에 대한 처리

@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        do_post_job()
    else:
        do_get_job()

디폴트는 GET이다.

- static 파일은 패키지에 static 디렉토리를 만들어서 거기에 넣어두면 /static으로 접근가능하다.

* static/style.css라는 파일이 있으면 아래와 같이 접근 가능

url_for('static', filename='style.css')

- flask는 Jinja2 템플릿 엔진을 사용한다. 물론 원하면 다른 엔진을 사용해도 된다.

패키지 안에 templates 디렉토리를 만들고 html 파일을 넣어둔다.
코드에서는 아래와 같이 접근 가능하다.

templates/hello.html 이 있는 경우

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)
hello.html은 아래와 같을 것이다.

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello World!</h1>
{% endif %}

html에서의 name은 render_template에 name argument로 넘겨준 값이 사용된다.

- 클라이언트가 보낸 데이타에 대한 처리를 위해 flask는 request object를 사용한다.

- URL에서 query parameter(?key=value)에 대한 처리는 아래와 같이 한다.

request.args.get('key', '')

- 파일 업로드하기
HTML form에서 enctype="multipart/form-data"로 해주어야 함

from flask import request

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/uploaded_file.txt')
    ...

업로드된 파일은 메모리나 임시 디렉토리에 저장되므로 save()함수를 사용하여 원하는 위치에 저장한다.
클라이언트쪽에서 사용했던 파일 이름을 알고 싶으면 f.filename을 사용하면 된다. 또는 좀 더 확실하게 알고 싶으면 secure_filename(f.filename)을 사용한다.

- Cookies

* 쿠키 읽기
request.cookies를 사용

from flask import request

@app.route('/')
def index():
    username = request.cookies.get('username')
    # use cookies.get(key) instead of cookies[key] to not get a
    # KeyError if the cookie is missing.

* 쿠키 저장하기
response object의 set_cookie()함수를 사용

from flask import make_response

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'sun')
    return resp

- redirect하고 싶으면 redirect()함수를, 바로 종료하고 싶으면 abort()함수를 사용한다.

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()

- 에러 페이지를 커스터마이즈하고 싶으면 app.errorhandler를 사용한다.

from flask import render_template

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

- Response object
a. 정상적인 response object가 함수로부터 리턴하면 이것이 바로 넘어간다.
b. string이 함수로부터 리턴하면 response object를 만들고 이것의 data로 string을 넘긴다.
c. tuple을 넘길 수 있는데 다음과 같은 형태가 되어야 한다. (response, status, headers)
d. 앞의 세 종류가 아니면 리턴 값을 response object로 변환한다.

- Session
session object를 통해 값을 가져오고 저장하고를 할 수 있다. session에는 아래의 예에서 처럼 secret key가 필요하다.

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)

@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form action="" method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))

# set the secret key.  keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'

- 로그가 필요하면 app.logger를 사용한다.

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')

- 구글 앱 엔진에 flask를 사용한 앱을 올리고 싶으면 아래의 내용 참조하라.
https://github.com/kamalgill/flask-appengine-template

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...