Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
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
Tags
more
Archives
Today
Total
관리 메뉴

나의 지식 보관소

Flask Quick Start / 플라스크 정리 본문

프로그래밍 언어/파이썬

Flask Quick Start / 플라스크 정리

야식은진리다 2021. 9. 22. 05:59

들어가기에 앞서

이 글은 후에 복습 목적으로 저의 얄팍한 영어를 사용해 https://flask.palletsprojects.com/en/2.0.x/quickstart/ 그대로 해석해서 올린 것임을 알립니다.

커맨드라인에서 실행하는 명령어 같은 경우 원글에서는 Bash Shell, CMD, Powershell등 종류마다 친절하게 기입되어있으나 제 글에서는 Bash 명령만을 기재하였으므로 CMD나 Powershell의 명령이 필요하시면 원글에서 확인해주시길 바랍니다.

혹 잘못된 해석이나 정보를 발견하셨을 경우 댓글에서 알려주시면 따뜻한 커피 한잔 대접해드리겠습니다.

 

Quickstart

플라스크를 시작하시길 원하시나요? 이 페이지는 플라스크 입문에 도움을 줄 것입니다. 먼저 플라스크 설치와 프로젝트 설정을 위해 설치 페이지를 따라주세요.

 

A Minimal Application

간단한 플라스크 어플리케이션은 다음과 같습니다:

from flask import Flask  app = Flask(__name__)  @app.route("/") def hello_world():     return "<p>Hello, World!</p>"

이 코드가 어떤 일을 할까요?

  1. 우선 Flask 클래스를 임포트했습니다. 이 클래스의 인스턴스가 우리의 WSGI 어플리케이션이 될 것입니다.
  1. 다음으로 이 클래스의 인스턴스를 생성했습니다. 첫번째 인자는 어플리케이션의 모듈 혹은 패키지의 이름입니다. __name__ 은 대부분의 경우에 적합한 편리한 숏컷입니다.
  1. 그런 다음 route() 데코레이터를 사용해서 어떤 url이 이 함수를 동작시킬지 Flask에게 알려줍니다.
  1. 함수는 우리가 유저의 웹브라우저에 표시하길 원하는 메세지를 반환해줍니다. 기본 콘텐츠 형식은 HTML입니다. 그러므로 문자열 안의 HTML이 브라우저에 의해 렌더링 될 것입니다.

 

이 코드를 hello.py 또는 비슷한 이름으로 저장합시다. Flask 자신과 충돌할 수 있기 때문에 파일명이 flask.py 가 되어서는 안됩니다.

 

어플리케이션을 실행 시키기 위해 flask 명령 또는 python -m flask 를 사용합니다. 명령을 실행하기 전에 어플리케이션이 작동할 수 있도록 터미널에 FLASK_APP 환경변수를 설정해주어야 합니다.

$ export FLASK_APP=hello $ flask run  * Running on http://127.0.0.1:5000/

Application Discovery Behavior:

만약 파일 이름을 app.py 또는 wsgi.py 로 설정했다면 FLASK_APP 환경 변수를 설정 할 필요가 없습니다. 자세한 정보는 Command Line Interface를 참고하세요.


이 명령은 테스트 하기에 충분히 괜찮은 간단한 빌트인 서버를 작동시키지만 프로덕션에서는 빌트인 서버를 사용하고 싶지 않을 수 있습니다. 배포 옵션을 확인하시려면 Deployment Options를 참고하세요.

 

이제 http://127.0.0.1:5000/로 가시면 Hello, World!가 나타나는 것을 보실 수 있습니다.


Externally Visible Server:

서버를 작동시키면 오직 자신의 컴퓨터에서만 서버에 접속 할 수 있다는것을 깨닳으실 것 입니다. 디버깅 모드에서는 어플리케이션 사용자가 컴퓨터에서 임의의 파이썬 코드를 실행시킬 수 있기 때문에 이것이 기본값입니다.

 

만약 디버거를 비활성화시켰거나 네트워크상의 다른 유저들을 신뢰한다면, 커맨드라인에 간단히 --host=0.0.0.0 를 추가하는 것으로 서버를 공개적으로 작동시킬수 있습니다.

$ flask run --host=0.0.0.0

이 명령은 모든 공개 아이피들을 접속할 수 있도록 하라고 OS에게 알립니다.


 

What to do if the Server does not Start

python -m flask 명령이 실패하거나 flask가 존재하지 않는 경우 여러가지 이유가 있을수 있습니다. 우선 에러 메세지를 확인하세요.

Old Version of Flask

0.11 버전보다 오래된 버전은 다른 어플리케이션 시작 방식을 사용하였습니다. 간단히 말하자면 flask 커맨드와 python -m flask 명령이 존재하지 않았습니다. 이런 경우엔 두가지 선택지가 있습니다: Flask의 버전을 업그레이드 하거나, 서버를 구동시킬 다른 방법을 보기 위해 Development Server 문서를 확인하십시오

Invalid Import Name

FLASK_APP 환경변수는 flask run 명령이 실행될 때 가져와지는 모듈의 이름입니다. 모듈명이 잘못되었을 경우 시작 시 임포트 오류가 발생합니다. 에러 메세지에 어떤 것을 임포트하려 하였고 왜 실패하였는지 표시됩니다.

 

가장 흔한 이유는 오타이거나, 사실 app 오브젝트를 생성하지 않았기 때문입니다.

 

Debug Mode

flask run 명령은 개발 서버를 시작하는 것 보다 더 많은 일을 할 수 있습니다. 디버그 모드를 활성화 시킴으로서 서버는 코드가 변경될 때 마다 자동적으로 리로드되고, request중에 오류가 발생할 경우 브라우저에 상호작용적인 디버거를 표시하여줍니다.


Warning:

이 디버거는 브라우저에서 임의의 파이썬 코드를 실행할 수 있도록 합니다. 이 기능은 pin의로 보호되긴 하지만 여전히 대표적인 주요 보안 위험입니다. 제품 환경에서는 개발서버 또는 디버거를 구동하지 마십시오.


모든 개발 기능을 사용가능하게 하기 위해 flask run 을 실행하기 전에 FLASK_ENV 환경변수를 development 로 설정하세요.

$ export FLASK_ENV=development $ flask run

참고 하세요:

 

 

HTML Escaping

HTML(플라스크의 기본 응답 유형)을 반환할 때, 출력에 렌더링된 유저가 제공한 모든 값들은 이스케이프하여 인젝션 어택으로부터 보호하여야 합니다. HTML 템플릿들을 렌더링하는 Jinja는 이것을 자동적으로 수행합니다.

 

여기서 보여지는 escape() 는 수동적으로 사용될 수 있습니다. 거의 모든 예제에서 간결함을 위해 생략되지만, 여러분은 신뢰할 수 없는 데이터를 어떻게 다루어야 하는지 항상 알고 있어야합니다.

from markupsafe import escape  @app.route("/<name>") def hello(name):     return f"Hello, {escape(name)}!"

만약 사용자가 <script>alert("bad")</script> 를 입력한다면, 유저의 브라우저에서 스크립트를 실행하는 것 대신 텍스트로서 렌더링합니다.

 

루트안의 <name> 은 URL로 부터 값을 가져와서 뷰 함수에 전달합니다. 이러한 변수 규칙들은 아래에서 설명합니다.

 

Routing

현대의 웹 어플리케이션은 사용자들을 돕기위해 의미있는 URL을 사용합니다. 페이지가 유저들이 기억할 수 있는 의미있는 URL을 사용하고 페이지를 직접 방문하는데 사용한다면 페이지를 더 좋아하고 다시 찾아올 가능성이 더 높습니다.

 

URL에 함수를 연결하기 위해 route() 데코레이터를 사용하세요.

@app.route('/') def index():     return 'Index Page'  @app.route('/hello') def hello():     return 'Hello, World'

URL을 동적으로 만들고 함수에 여러 규칙을 부착하는등 더 많은걸 할 수 있습니다.

 

Variable Rules

<variable_name> 섹션을 URL에 만듦으로서 URL에 변수 섹션을 추가할 수 있습니다. 이 함수는 <variable_name> 을 키워드 인자로서 전달 받습니다. 선택적으로 인자의 형식을 지정하기위해 <converter:variable_name> 처럼 컨버터를 사용할 수도 있습니다.

from markupsafe import escape  @app.route('/user/<username>') def show_user_profile(username):     # show the user profile for that user     return f'User {escape(username)}'  @app.route('/post/<int:post_id>') def show_post(post_id):     # show the post with the given id, the id is an integer     return f'Post {post_id}'  @app.route('/path/<path:subpath>') def show_subpath(subpath):     # show the subpath after /path/     return f'Subpath {escape(subpath)}'

컨버터 형식:

  • string: (기본값) 슬래시를 제외한 모든 텍스트를 받습니다.
  • int: 양수를 입력 받습니다.
  • float: 양의 실수를 입력받습니다.
  • path: string과 비슷하지만 슬래시도 입력받습니다.
  • uuid: UUID 문자열을 입력받습니다.

 

 

Unique URLs / Redirection Behavior

아래의 두가지 규칙은 끝의 슬래시 사용에서 다릅니다.

@app.route('/projects/') def projects():     return 'The project page'  @app.route('/about') def about():     return 'The about page'

projects 엔드포인트의 표준 URL에는 후행 슬래시가 있습니다. 이것은 파일 시스템의 폴더와 유사합니다. 만약 유저가 후행 슬래시 없이 URL에 접근한다면(/projects) 플라스크가 유저를 후행 슬래시와 함께 표준 URL로 리다이렉트 합니다(/projects/).

 

about 엔드포인트의 표준 URL은 후행 슬래시를 가지고 있지 않습니다. 이것은 파일의 pathname과 비슷합니다. 후행 슬래시와 함께 접근하는것(/about/)은 404 "Not Found" 에러를 발생시킵니다. 이렇게 하면 이러한 리소스들이 고유한 URL을 유지하여 검색 엔진이 동일한 페이지를 두 번 인덱싱하는 것을 방지할 수 있습니다.

 

URL Building

특정한 함수의 URL을 빌드하기 위해 url_for() 함수를 사용합니다. 이 함수는 함수의 이름을 함수의 첫번째 인자로써 전달 받고 각각 URL 규칙의 변수 부분에 상응하는 키워드 인자를 전달 받습니다. 알 수 없는 변수 부분은 URL의 쿼리 매개변수로서 첨부됩니다.

 

왜 템플릿안에 URL을 하드코딩해서 때려박기보단 URL리버싱 함수인 url_for()를 사용할까요?

  1. 리버싱 함수가 하드코딩된 URL보다 대부분의 경우에서 가독성이 좋습니다.
  1. URL을 변경할때 수동으로 하크코딩된 URL을 기억하고 바꿀 필요 없이 한번에 변경할수 있습니다.
  1. URL building은 특수문자 이스케이프를 투명하게 처리합니다.
  1. 생성된 경로는 언제나 절대 경로이므로 브라우저에서 상대경로의 에기치 않은 동작이 방지됩니다.
  1. 만약 어플리케이션이 / 대신 /myapplication 처럼 URL 루트의 바깥에 위치해 있다면, url_for()이 적절히 처리하여 줍니다.

 

 

예를 들어, 이 예제는 url_for()를 시험해보기위해 test_request_context() 메서드를 사용합니다. test_request_context() 는 파이썬 셸을 이용하는 동안에도 마치 Flask가 요청을 처리하는것처럼 행동하도록 지시합니다. Context Locals를 참고하세요.

from flask import url_for  @app.route('/') def index():     return 'index'  @app.route('/login') def login():     return 'login'  @app.route('/user/<username>') def profile(username):     return f'{username}\'s profile'  with app.test_request_context():     print(url_for('index'))     print(url_for('login'))     print(url_for('login', next='/'))     print(url_for('profile', username='John Doe'))
/ /login /login?next=/ /user/John%20Doe

 

HTTP Methods

웹 어플리케이션은 URL에 접근할때 각기 다른 HTTP 메서드를 사용합니다. Flask로 일하면서 HTTP 메서드들에 친숙해져야 합니다. 기본적으로, 루트는 오직 GET 요청에 대해서만 응답합니다. route() 데코레이터의 methods 인자를 사용해서 다른 HTTP 메서드를 사용할 수 있습니다.

from flask import request  @app.route('/login', methods=['GET', 'POST']) def login():     if request.method == 'POST':         return do_the_login()     else:         return show_the_login_form()

만일 GET 이 있다면 플라스크는 자동적으로 HEAD 메서드에 대한 지원을 추가하고 HTTP RFC를 따라 HEAD 요청을 처리합니다. 비슷하게, OPTIONS 는 자동적으로 구현됩니다.

 

Static Files

동적 웹 어플리케이션은 또한 정적 파일을 필요로 합니다. 주로 CSS와 JavaScripts 파일이 이에 해당합니다. 이상적으로 웹서버가 그것들을 수행할 수 있도록 구성되지만, Flask 개발중에도 이를 수행할 수 있습니다. 그저 static 폴더를 패키지 안이나 모듈 옆에 생성하면 어플리케이션에서 /staic 을 사용할 수 있게됩니다.

 

static file을 위한 URL 생성을 위해 특별한 'static' 엔드포인트 네임을 사용합니다.

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

해당 파일을 파일 시스템에 statuc/style.css 로서 저장되어 있습니다.

 

Rendering Templates

파이썬 내에서 HTML을 생성하는것은 그닥 즐거운 일이 아닙니다 그리고 어플리케이션 보안을 지키기 위해 HTML 이스케이핑을 스스로 수행하여야 하기 때문에 사실 꽤 성가십니다. 이러한 점 때문에 플라스크는 자동적으로 Jinja2 템플릿 엔진을 구성하여줍니다.

 

템플릿을 렌더링 하기 위해서는 render_template() 메서드를 사용합니다. 우리가 해야할 일은 템플릿의 이름과 템플릿 엔진에 키워드 인자로써 전달하고 싶은 변수를 제공하는 것이 전부입니다. 여기 어떻게 템플릿을 렌더하는지에 관한 간단한 예제입니다.

from flask import render_template  @app.route('/hello/') @app.route('/hello/<name>') def hello(name=None):     return render_template('hello.html', name=name)

플라스크는 템플릿들을 templates 폴더에서 찾습니다. 만약 어플리세이션이 모듈이라면 이 폴더는 모듈옆에 위치합니다. 만약 어플리케이션이 패키지라면 이 파일은 패키지 안에 위치합니다.

 

Case 1

: 모듈일 때:

/application.py /templates     /hello.html
Case 2

: 패키지일 때:

/application     /__init__.py     /templates         /hello.html

 

템플릿의 경우 Jinja2 템플릿의 풀 파워를 사용할 수 있습니다. 더 많은 정보를 위해 Jinja2 공식 Jinja2 Template Documentation 를 확인하세요.

 

여기 예제 템플릿이 있습니다:

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

템플릿 안에서 config, request, session 그리고 g 객체에 뿐만 아니라 url_for()get_flashed_message() 함수에 접근할 수 있습니다.

 

템플릿들은 상속이 사용되었을 때 특별히 유용합니다. 만약 상속이 어떻게 작동하는지 알고 싶다면 Template Inheritance 문서를 확인하세요. 기본적으로 템플릿 상속은 특정한 요소(header, naviation, footer같은)가 각 페이지에서 유지될 수 있도록 합니다.

 

자동 이스케이핑이 활성화 되어있어서 만약 name 이 HTML을 포함하고 있다면 자동적으로 이스케이프될 것 입니다. 만일 값을 믿을 수 있고 안전한 HTML일것임을 안다면 (예를 들어 위키의 마크업을 HTML로 바꾸는 모듈에서 온 값이라거나) Markup 클래스나 템플릿의 |safe 필터를 사용함으로써 안전하다고 표시할 수 있습니다. 더많은 예를 원한다면 Jinja 2 문서를 확인하세요.

 

여기 어떻게 Markup 클래스가 작동하는지에 대한 소개가 있습니다:

>>> from markupsafe import Markup >>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' Markup('<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>') >>> Markup.escape('<blink>hacker</blink>') Markup('&lt;blink&gt;hacker&lt;/blink&gt;') >>> Markup('<em>Marked up</em> &raquo; HTML').striptags() 'Marked up \xbb HTML'
  • Changelog

    0.5버전에서 수정됨: 자동 이스케이핑은 이제 더이상 모든 템플릿에서 사용가능하지 않습니다. .html , .htm , .xml , .xhtml 의 확장자를 가진 템플릿들만이 자동 이스케이핑을 작동시킵니다. 문자열로부터 로드된 템플릿들은 자동 이스케이핑이 비활성화된 상태로 로드됩니다.

💡
g 객체가 무엇인지 확실하지 않나요? g객체는 필요에 의한 정보들을 저장할 수 있는 무언가입니다. flask.g에 관한 문서를 확인하려면 flask.gUsing SQLite 3 with Flask 문서를 확인하세요.

 

Accessing Request Data

웹 어플리케이션에게 클라이언트가 서버에 보내는 데이터에 반응하는것은 중요합니다. 플라스크에서 이러한 정보는 전역 request 개체에 의해서 전달되어집니다. 만약 파이썬을 다루어본적이 몇번 있다면 어떻게 request 개체가 전역이 될 수 있는지 그리고 플라스크가 어떻게 threadsafe하게 관리할수 있는지 궁금하실겁니다. 답은 context locals에 있습니다.

 

Context Locals


Insider Information:

만약 이것이 어떻게 동작하는지, 또 어떻게 context local과 함께 테스트를 시행할 수 있는지 이해하시길 원하신다면, 이 섹션을 읽으세요, 그렇지 않다면 건너뛰셔도 됩니다.


플라스크의 특정한 개체는 전역 개체이지만 일반적인 종류는 아닙니다. 이러한 개체들은 사실 특정 컨텍스트의 로컬 개체의 대리입니다. 어렵게 느껴질지 모르겠지만 사실 이해하기 꽤 쉽습니다.

 

컨텍스트가 핸들링 스레드라고 상상해봅시다. 요청이 들어오고 웹서버는 새로운 스레드를 생성하기로 마음먹습니다.(또는 스레드 말고 동시성 시스템을 다룰 능력이 있는 개체라고 상상해봅니다.) 플라스크가 내부 요청 처리를 시작하면 현재 스레드가 활성 컨텍스트임을 파악하고 현재 어플리케이션과 WSGI 환경을 해당 컨텍스트(스레드)에 바인딩 합니다. 한 응용프로그램이 다른 응용 프로그램을 중단 없이 호출 할 수 있도록 지능적인 방식으로 이 작업을 수행합니다.

 

이것이 의미하는 바가 무엇일까요? 단위 테스트와 같은 작업을 하지 않는 한 기본적으로 이러한 경우를 완전히 무시할 수 있습니다. request 개체가 없기때문에 request 개체에 의존하는 코드는 갑작스럽게 중단될 수 있음을 깨닳으실겁니다. 해결방법은 request 개체를 스스로 만들고 컨텍스트에 바인딩하는 것입니다. 단위 테스트에서 가장 쉬운 방법은 test_request_context() 를 사용하는 것입니다. with문과 함께 사용하여 테스트 request를 바인드하고 상호작용 할 수 있습니다. 여기 그 예시 입니다.

from flask import request  with app.test_request_context('/hello', method='POST'):     # now you can do something with the request until the     # end of the with block, such as basic assertions:     assert request.path == '/hello'     assert request.method == 'POST'

또다른 가능성은 request_context() 메서드에 전체 WSGI 환경을 전달하는 것입니다:

with app.request_context(environ):     assert request.method == 'POST'

 

The Request Object

request 개체는 API 섹션에 정리되어있으며 여기서 자세히 다루지 않습니다(Requset를 보세요). 여기서는 자주 쓰이는 공통 작업의 개요를 살핍니다. 먼저 flask 모듈을 임포트합니다.

from flask import request

현재의 request 메서드는 method 속성을 사용함으로서 사용가능합니다. 폼 데이터(POST 또는 PUT request로 전달된 ) 에 접근하기 위해 form 속성을 사용할 수 있습니다. 여기 위에 언급된 두가지 속성의 예제입니다.

@app.route('/login', methods=['POST', 'GET']) def login():     error = None     if request.method == 'POST':         if valid_login(request.form['username'],                        request.form['password']):             return log_the_user_in(request.form['username'])         else:             error = 'Invalid username/password'     # the code below is executed if the request method     # was GET or the credentials were invalid     return render_template('login.html', error=error)

form 속성에 만일 key가 존재하지 않는다면 어떻게 될까요? 이 경우 특별한 KeyError가 발생합니다. 평범한 KeyError 처럼 예외처리를 할 수 있지만 만약 예외처리를 하지 않는다면 HTTP 400 Bad Request 에러 페이지가 대신 표시됩니다. 그래서 많은 경우 이 문제를 다루지 않아도 됩니다.

 

URL에 전달된 매개변수(?key=value)에 접근하기 위해서 args속성을 사용할 수 있습니다.

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

URL 매개변수에 get 또는 KeyError를 예외처리 함으로써 접근하는것을 권장합니다 왜냐하면 유저가 URL을 변경할 수 있고 이 경우 나타나는 400 bad reequest 페이지는 유저 친화적이지 않습니다.

 

request 개체의 모든 메서드와 속성 리스트를 확인하기 위해서는 Request 문서를 참조하십시오

 

File Uploads

Flask를 이용하여서 업로드된 파일들을 쉽게 다룰 수 있습니다. HTML 폼에 enctype="multipart/form-data" 속성을 설정하는 것을 잊지만 않으면 됩니다. 그렇지않으면 브라우저는 파일을 전혀 전송할 수 없습니다.

 

업로드된 파일들은 메모리나 파일시스템의 임시적인 장소에 저장됩니다. 이러한 파일들은 request 개체의 files 속성을 이용하여 접근할 수 있습니다. 각각의 업로드된 파일은 딕셔너리에 저장되어 Python 표준 file 개체처럼 작동하지만 추가로 서버의 파일시스템에 해당 파일을 저장할 수 있도록 해주는 save() 메서드를 가집니다. 여기 이것이 어떻게 작동하는지 보여주는 예시입니다.

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')     ...

만약 어플리케이션에 업로드 되기 전 클라이언트에서 파일명이 어떻게 정해지는지 알고 싶다면 filename 속성을 살펴보십시오. 하지만 이 값은 변조될 수 있음을 명심하고 절대적으로 신뢰하지는 마십시오. 만약 파일을 서버에 저장할 때 클라이언트의 파일명을 사용하고 싶다면, Werkzeug가 제공하는 secure_filename() 함수를 통하여 전달하세요.

from werkzeug.utils import secure_filename  @app.route('/upload', methods=['GET', 'POST']) def upload_file():     if request.method == 'POST':         file = request.files['the_file']         file.save(f"/var/www/uploads/{secure_filename(file.filename)}")     ...

더 나은 에제를 보려면 Uploading Files를 참조하세요.

 

Cookies

쿠키에 접근하기 위해서 cookies 속성을 이용하실 수 있습니다. 쿠키를 설정하기 위해서는 response 개체의 set_cookie 메서드를 사용할 수 있습니다. request 개체의 cookies 속성은 클라이언트가 전송한 모든 쿠키가 포함된 딕셔너리입니다. 만약 세션을 사용하기를 원한다면, 쿠키를 직접 사용하지 말고 쿠키에 보안이 추가된 Flask의 Sessions를 사용하세요.

 

쿠키를 읽는법:

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.

쿠키 저장하는 법:

from flask import make_response  @app.route('/') def index():     resp = make_response(render_template(...))     resp.set_cookie('username', 'the username')     return resp

쿠키들은 response 개체에 설정됩니다. 보통 view 함수들은 문자열을 반환하기 때문에 Flask는 이를 response 개체로 변환합니다. 만약 명시적으로 그렇게 하길 원한다면 make_respnse() 함수를 사용해서 수정할 수 있습니다.

 

reponse 개체가 아직 존재하지 않을 때 쿠키를 설정하고 싶을 수도 있습니다. 이것은 Deferred Request Callbacks 패턴을 이용하여 할 수 있습니다.

 

이것을 위해 About Responses 도 참고하세요.

 

Redirects and Errors

유저를 다른 endpoint로 리다이렉트하기 위해서는 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()

이것은 사용자가 인덱스에서 접근할 수 없는 페이지로 리다이렉션(401은 접근 거부를 뜻합니다.)되기 때문에 다소 무의미한 예제이지만 작동 방식을 보여줍니다.

 

기본적으로 각 에러코드마다 흑백 오류 페이지가 표시됩니다. 오류 페이지를 커스텀하기를 원하신다면, errorhandler() 데코레이터를 사용하실 수 있습니다.

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

render_template() 뒤에 오는 404 에 주의하십시오. 이것은 플라스크에게 해당 페이지의 상태 코드가 찾을 수 없을을 의미하는 404이여야 한다는 것을 알려줍니다. 기본값은 모든게 잘 도착했음을 의미하는 200입니다.

 

더 많은 세부사항을 보고 싶다면 Handling Application Errors을 참조하세요.

 

About Responses

뷰 함수의 반환 값은 자동적으로 response 개체로 변환됩니다. 만약에 반환 값이 문자열이라면 반환 값은 문자열은 response body으로써 함께 200 OK 상태 코드 그리고 text/html mimetype 인 response 개체로 변환됩니다. 만약 반환 값이 딕셔너리라면, response를 만들기 위해 jsonify() 가 호출됩니다. Flask가 반환 값을 response 개체로 변환하는데 적용하는 로직은 다음과 같습니다.:

  1. 만약 알맞은 타입의 response 개체가 반환되었다면 뷰에서 부터 바로 반환됩니다.
  1. 만약 문자열이라면, 기본 매개변수와 해당 대이터로 response 개체가 생성됩니다.
  1. 만약 딕셔너리라면, jsonify 를 사용하여 response개체를 생성합니다.
  1. 만약 튜플이 반환되었다면 튜플안의 아이템들이 추가적인 정보를 제공할 수도 있습니다. 이러한 튜플은 (response, status) , (reponse, headers), 또는 (response, status, header) 형식이어야 합니다. status 값은 상태코드를오버라이드 하고 headers 는 추가적인 헤더 값들의 리스트나 딕셔너리가 될수 있습니다.
  1. 이것들중 해당하지 않는다면, 플라스크는 반환값을 유효한 WSGI 어플리케이션으로 추정하고 response개체로 변환할 것 입니다.

 

만약 뷰 내에서 결과 response 객체를 유지하려면 make_response() 함수를 사용할 수 있습니다.

 

이런 뷰가 있다고 상상해 보세요:

from flask import render_template  @app.errorhandler(404) def not_found(error):     return render_template('error.html'), 404

 

반환 식을 그저 make_reponse()로 감싸고 수정하기위해 response 객체를 얻어서 리턴하면 됩니다.

from flask import make_response  @app.errorhandler(404) def not_found(error):     resp = make_response(render_template('error.html'), 404)     resp.headers['X-Something'] = 'A value'     return resp

 

APIs with JSON

API를 작성할 때 일반적인 response 포맷은 JSON입니다. Flask로 이러한 API 작성을 시작하는 것은 쉽습니다. 만약 뷰에서 dict 을 반환한다면, JSON response로 변환될 것입니다.

@app.route("/me") def me_api():     user = get_current_user()     return {         "username": user.username,         "theme": user.theme,         "image": url_for("user_image", filename=user.image),     }

당신의 API 디자인에 따라 dict 이외의 유형에 대한 JSON resonses 생성을 원할수 도 있습니다. 이러한 경우, 모든 지원되는 JSON 데이터 타입을 직렬화하는 jsonify() 함수를 사용하세요. 또는 더 복잡한 어플리케이션을 지원하는 Flask 커뮤니티 익스텐션들을 살펴보세요.

from flask import jsonify  @app.route("/users") def users_api():     users = get_all_users()     return jsonify([user.to_json() for user in users])

 

Sessions

추가로 request 객체에는 한 요청에서 다음 요청 까지 사용자에 대한 특정 정보를 저장할 수 있는 session이라고 불리는 두번째 객체가 있습니다. 이것은 당신을 위해 쿠키위에 구현되며 쿠키에 암호학적로 서명합니다. 이것은 사용자가 서명에 사용된 비밀 키를 알지 못하는 한 콘텐츠를 볼 수는 있지만 수정할 수 없다는 것을 의미합니다.

 

세션을 사용하기 위해서 비밀키를 설정 해야합니다. 이 예제는 세션이 어떻게 일하는지 보여줍니다.:

from flask import session  # Set the secret key to some random bytes. Keep this really secret! app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'  @app.route('/') def index():     if 'username' in session:         return f'Logged in as {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 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'))

How to generate good secret keys:

비밀키는 가능한 랜덤이여야 합니다. 운영체제는 암호학적인 랜덤 생성에 기반한 꽤 괜찮은 랜덤 데이터 생성 방식을 가지고 있습니다. 빠르게 Flask.secret_key (또는 SECRET_KEY)의 값을 생성하기 위해 아래의 커맨드를 사용하세요.:

 

$ python -c 'import os; print(os.urandom(16))'

b'_5#y2L"F4Q8z\n\xec]/'


 

쿠키 기반 세션에 대한 참고 사항: Flask는 세션 개체에 넣은 값을 쿠키로 직렬화 합니다. 요청 간에 지속되지 않는 값을 원한다면, request 가 가능합니다. 그리고 명확한 에러메세지를 받지 못하고 있다면 웹브라우저가 지원하는 쿠키 사이즈와 페이지 응답의 쿠키 사이즈를 확인하세요.

 

뿐만아니라 기본 클라이언트 측 기반 세션 외에도 서버측에서 세션을 대신 처리하려는 경우 이를 지원하는 여러 Flask 확장이 있습니다.

 

Message Flashing

좋은 어플리케이션과 유저 인터페이스는 모두 피드백에서 나옵니다. 만약 유저가 충분한 피드백을 받지 못한다면 결국 어플리케이션을 싫어하게 될지도 모릅니다. Flask는 flashing system을 통해 유저에게 피드백을 제공할 정말 간단한 방법을 제공합니다. flashing 시스템은 기본적으로 요청이 끝날 때 메세지를 기로가고 다음(그리고 다음에만) 요청에 액세스 할 수 있습니다. 이것은 일반적으로 메세지를 노출하기 위해 레이아웃 템플릿과 결합됩니다.

 

메세지를 플래시하기 위해서는 flash() 메서드를 사용합니다. 메세지를 보관하기위해 템플릿에서 사용가능한 get_flashed_message() 를 사용할 수 있습니다. 전체 예제를 보기 위해서는 Message Flashing 을 참고하세요.

 

Logging

  • Changelog

    New in version 0.3.

때로는 정확해야 하지만 실제로는 그렇지 않은 데이터를 처리해야 하는 상황에 처할 수 있습니다. 예를 들어, 클라이언트 측에서 잘못된 형식의 HTTP request를 서버로 보내는 코드가 있을 수 있습니다. 이것은 유저가 데이터를 변조하였거나 클라이언트의 코드가 실패하므로서 발생할 수 있습니다. 대부분의 경우 400 Bad Request 로 응답하면 됩니다. 하지만 때때로 그렇지 않고 코드가 계속 진행될 수도 있습니다.

 

이런 수상한 일이 벌어졌을때 로그를 남기고 싶을 수 있습니다. 여기서 로거가 유용합니다. Flask 0.3부터는 로거가 사용할 수 있도록 미리 구성되어있습니다.

 

여기 로그가 불려진 몇몇 예제입니다.

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

첨부된 logger는 표준 로깅 logger이므로 자세한 참고 내용은 공식 logging 문서를 참조하세요.

 

Handling Application Errors를 확인하세요.

 

Hooking in WSGI Middleware

WSGI 미들웨어를 Flask 어플리케이션에 추가하고 싶다면, 어플리케이션의 wsgi_app 속성을 래핑하세요. 예를 들어, Nginx 뒤에서 실행하기 위해 Werkzeug의 Proxyfix 미들웨어를 적용하려면:

from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app)

app 대신 app.wsgi_app 을 래핑하는것은 app 이 미들웨어가 아니라 여전히 Flask 어플리케이션을 가르키고 있다는 것을 의미합니다. 그러므로 app 을 계속 직접적으로 사용하고 설정할 수 있습니다.

 

Using Flask Extensions

확장은 일반적인 업무를 성취할 수 있도록 돕는 패키지입니다. 예를 들어, Flask-SQLAlchemy 는 Flask와 함께 사용하기 쉽고 간편하게 만들어 주는 SQLAlchemy 도움을 제공합니다.

 

더 많은 Flask 확장을 보시려면 Extensions를 확인하세요.

 

Deploying to a Web Server

Flask 앱을 배포할 준비가 되셨나요? Deployment Options를 확인하세요.