해당 글은 공부를 위해 https://flask.palletsprojects.com/en/1.1.x/tutorial/views/ 을 번역한 글입니다.
View 함수는 애플리케이션에 대한 요청에 응답하기 위해 작성하는 코드이다.
Flask는 패턴을 사용하여 수신 요청 URL을 처리해야하는 View에 일치시킨다.
View는 Flask가 발신 응답으로 변환하는 데이터를 반환한다.
Flask는 다른 방향으로 이동하여 이름과 인수를 기반으로 View에 대한 URL을 생성할 수 있다.
하나의 Blueprint는 관련 뷰 및 기타 코드 그룹을 구성하는 방법이다.
뷰 및 기타 코드를 애플리케이션에 직접 등록하는 대신 Blueprint에 등록한다.
그런 다음 Factory 함수에서 사용할 수 있을 때, Blueprint는 응용 프로그램에 등록된다.
Flaskr 에는 두 개의 Blueprint가 있는데 하나는 인증 기능용이고, 다른 하나는 블로그 게시물 기능용이다.각 Blueprint에 대한 코드는 별도의 모듈로 이동한다.블로그에서 인증에 대해 알아야하므로 먼저 인증을 작성하자.
# flaskr/auth.py
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash
from flaskr.db import get_db
bp = Blueprint('auth', __name__, url_prefix='/auth')
'auth' 라는 이름을 가진 Blueprint 를 생성한다.
애플리케이션 객체와 마찬가지로 Blueprint는 정의된 위치를 알아야하므로 __name__
을 두번째 인수로 전달된다.
url_prefix 는 Blueprint와 관련된 모든 URL 앞에 추가된다.
# flaskr/__init__.py
def create_app():
app = ...
# existing code omitted
from . import auth
app.register_blueprint(auth.bp)
return app
app.register_blueprint()
를 사용하여 Factory에서 Blueprint를 가져오고 등록한다.
앱을 반환하기 전에 Factory 함수 끝에 새 코드를 배치한다.
인증 Blueprint에는 새 사용자를 등록하고 로그인 및 로그아웃하는 보기가 있을 것이다.
사용자가 /auth/register URL에 방문하면 register 뷰는 사용자가 작성할 양식과 함께 HTML을 반환한다.
양식을 제출하면 입력 내용을 확인하고 오류 메시지와 함께 양식을 다시 표시하거나 새 사용자를 만들고 로그인 페이지로 이동한다.
# flaskr/auth.py
@bp.route('/register', methods=('GET', 'POST'))
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
if not username:
error = 'Username is required.'
elif not password:
error = 'Password is required.'
elif db.execute(
'SELECT id FROM user WHERE username = ?', (username,)
).fetchone() is not None:
error = 'User {} is already registered.'.format(username)
if error is None:
db.execute(
'INSERT INTO user (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
db.commit()
return redirect(url_for('auth.login'))
flash(error)
return render_template('auth/register.html')
@bp.route
는 URL /register를 register 뷰 함수와 연결한다.'POST'
이다.fetchone()
은 쿼리에서 한 행을 반환한다. 쿼리가 결과를 반환하지 않으면 None으로 반환된다.fetchall()
을 사용하여 모든 결과의 목록을 반환한다.generate_password_hash()
를 사용하여 암호를 안전하게 해시하고 해당 해시가 저장된다.db.commit()
를 나중에 호출해야 한다.flash()
는 템플릿을 렌더링 할 때 검색할 수 있는 메시지를 저장한다.render_template()
는 HTML이 포함된 템플릿을 렌더링하며, 이 템플릿은 다음 tutorial에서 작성한다.Login 뷰는 Register 뷰와 비슷한 패턴을 가진다.
# flaskr/auth.py
@bp.route('/login', methods=('GET', 'POST'))
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
user = db.execute(
'SELECT * FROM user WHERE username = ?', (username,)
).fetchone()
if user is None:
error = 'Incorrect username.'
elif not check_password_hash(user['password'], password):
error = 'Incorrect password.'
if error is None:
session.clear()
session['user_id'] = user['id']
return redirect(url_for('index'))
flash(error)
return render_template('auth/login.html')
register 뷰 몇가지 차이점이 있다.
check_password_hash()
는 제출된 암호를 저장된 해시와 동일한 방법으로 해시하고 안전하게 비교한다.이제 사용자의 ID가 세션에 저장되었으므로, 이후 요청 시 사용할 수 있게 된다.
각 요청이 시작될 때 사용자가 자신의 정보에 로그인한 경우 로드하여 다른 보기에 제공해야 한다.
# flaskr/auth.py
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
bp.before_app_request()
는 어떤 URL을 요청하든 View 함수보다 먼저 실행되는 함수를 등록한다.
load_logged_in_user()는 사용자 ID가 세션에 저장되어 있는지 확인하고, 데이터베이스에서 해당 사용자의 데이터를 가져와 g.user에 저장하며, 요청 기간동안 지속된다.
사용자 ID가 없거나 ID가 존재하지 않는 경우, g.user는 None 이다.
로그아웃하려면 세션에서 사용자 ID를 제거하면 된다.
그러면 load_logged_in_user 는 후석 요청에 대해 사용자를 로드하지 않는다.
# flaskr/auth.py
@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
블로그 게시물 작성, 편집 및 삭제하려면 사용자가 로그인해야 한다.
Decorator 를 사용하여 적용되는 각 View에 대해 이를 확인할 수 있다.
# flaskr/auth.py
def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))
return view(**kwargs)
return wrapped_view
Decorator 는 적용된 원래 뷰를 래핑하는 새로운 뷰 함수를 반환한다.
새 함수는 사용자가 로드되었는지 확인하고 그렇지 않은 경우 Login 페이지로 Redirect 한다.
사용자가 로드된 경우 원래 View가 호출되고 정상으로 계속된다.