https://flask.palletsprojects.com/en/2.0.x/tutorial/views/
청사진(Blue prints)와 views
뷰 함수는 당신의 어플리케이션에 요청에 응답하기 위해 작성하는 코드 입니다. 플라스크는 패턴을 사용하여 뷰에 대해 들어오는 요청 URL이 일치하도록 하여 이것을 핸들링하도록 합니다. 뷰는 앞으로 응답에 대해 플라스크가 전환되는 데이터를 돌려줍니다. 플라스크는 또한 다른 방향을 향해 갈 수 있고 name과 argument들에 기반한 뷰에 대한 URL을 생성합니다.
청사진(Blueprint) 생성
블루프린트는 다른 코드와 뷰들에 연관된 그룹을 구성하는 방법입니다. 뷰들과 다른 코드를 어플리케이션에 직접적으로 등록하는 것보다, 블루프린트(청사진)에 등록됩니다. 그리고 나면 청사진은 팩토리 함수에서 이용가능할 때 어플리케이션에 등록됩니다.
Flaskr은 두가지 청사진을 가질 것입니다, 하나는 authentication (인증) 함수들을 위한 것이고, 하나는 블로그 포스트 함수들을 위한 것입니다. 각 청사진을 위한 코드는 각각의 모듈 안에서 동작하게 될 것입니다. 블로그가 인증(authenticaiton) 에 대해 알 필요가 있기 때문에, 당신은 인증 을 먼저 작성할 것입니다.
Flask/auth.py
import functools
펑크툴을 임포트 합니다.
from flask import (
Blueprint, flash, g, redirect, render_template, request, session,
url_for
)
Blueprint, flash, g ,redirect, render_template, request, session, url_for를 플라스크에서 임포트 합니다.
from werkzeug.security import check_password_hash, generate_password_hash
werkzeug.security에서 패스워드 체크 해쉬 함수, 패스워드 해쉬 재너레이트 함수를 임포트 합니다.
from flask.db import get_db
bp = Blueprint(‘auth’, __name__, url_prefix =‘/auth’)
청사진에 ‘auth’ 를 등록합니다.
이것은 ‘auth’라는 이름의 청사진을 생성합니다. 어플리케이션 객체와 같이, 청사진은 어디서 이것이 정의되었는지 알 필요가 있습니다, 따라서 __name))은 두번째 인자로 넘겨집니다. Url_prefix는 해당 청사진과 연관된 모든 URL들에게 앞에 붙여질 것입니다.
app.register_blueprint()를 사용하여 팩토리로부터 청사진을 임포트하고 등록하세요. app을 리턴하기 전에 팩토리 함수의 맨 끝에 새로운 코드를 위치시킵니다.
flaskr/__init__.py
def create_app():
app=…
#existing code omitted
from . import auth
app.register_blueprint(auth.bp)
return app
인증(authentication) 청사진은 새로운 유저를 등록하고 로그인하고, 로그아웃하기 위한 뷰들을 가지게 될 것입니다.
첫번째 뷰: 등록(register)
사용자가 /auth/register URL을 방문할때, register 뷰는 HTML을 채우기 위한 form과 HTML을 반환할 것입니다. 그들이 form을 제출할때, 그들의 입력값이 유효한지 확인하거나 에러 메시지와 함께 폼을 다시 보이거나 새로운 유저를 만들고 로그인 페이지로 이동하게 될 것입니다.
현재로써 당신은 뷰 코드를 작성하면 됩니다. 다음 페이지에서, 당신은 HTML form을 생성하기 위한 템플릿을 작성할 것입니다.
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 requried.
”
if error is None:
try:
db.execute(
“INSERT INTO user (username, password) VALEUS (?, ?)”,
(username, generated_password_hash(passwor d)),
)
db.commit()
except db.IntegrityError:
error = f”User {username} is already registered”
else:
return redirect(url_for(“auth.login”))
flash(error)
return render_templated(‘auth/register.html’)
여기 register 뷰 함수가 하는 일이 있습니다.
- @bp.route는 register view 함수와 URL /register 과 연관되어있습니다. 플라스크가 /auth/register에 요청을 받을때, 이것은 register 뷰를 호출하고 값과 응답을 반환 할 것입니다.
- 만약 사용자가 폼을 제출했다면, request.method 는 POST일 것입니다. 이경우 입력값에 대한 검증을 시작합니다.
- request.form 은 특별한 형태의 키와 값을 맵핑하는 제출하는 폼 인 dict 형태입니다. 사용자는 사용자이름과 패스워드를 입력할 것입니다.
- 사용자이름과 패스워드가 비어있지 않다는 것을 검증합니다.
- 만약 검증이 성공한다면, 데이터베이스에 새로운 사용자 데이터를 넣습니다.
- 유저를 저장한 후에, 로그인 페이지로 리다이텍트 됩니다. Url_for()는 이것의 이름에 기반한 로그인 뷰를 위한 URL을 생성합니다. 이것은 연결되는 모든 코드의 변환없이 추후 URL을 변경하도록 허락하는데 직접적으로 작성할 때 유용합니다. redirect()는 생성된 URL에 리다이렉트 응답을 생성합니다.
- 만약 검증(validation)이 실패한다면, 에러는 유저에게 보여집니다. Flash()는 템플릿을 랜더링할 때 나올 수 있는 메시지를 저장합니다.
- 사용자가 auth/register를 초기 탐색할때, 혹은 검증 오류가 있었을때, HTML 페이지는 등록과 함께 보여져야합니다. render_template()은 당신이 튜토리얼의 다음 스텝에서 작성할 HTML을 포함한 템플릿을 렌더링 할 것입니다.
로그인
이 뷰는 위에 있는 reigster과 동일한 패턴을 따릅니다.
reigster view와 몇가지 차이점이 있습니다.
- 유저는 나중의 사용을 위해 변수에 저장되고 우선 쿼리됩니다. Fetchone()은 쿼리로부터 하나의 row를 반환합니다. 만약 쿼리가 아무 결과도 리턴하지 않는다면, 이것은 None을 리턴합니다. 나중에 fetchall()이 사용될 것인데, 이것은 모든 결과의 리스트를 리턴합니다.
- check_password_hash() 저장된 해쉬와 같은 방식으로 제출된 패스워드들을 해싱합니다. 그리고 안전하게 그들을 비교합니다. 만약 그들이 일치한다면, 패스워드는 유효합니다.
- 세션은 요청을 across한 데이터를 저장하는 dict 입니다. 검증이 성공할때,사용자의 아이디는 새로운 세션에 저장됩니다. 데이터는 브라우저에 보내진 쿠키에 저장됩니다, 그리고 브라우저는 서브시퀀트 요청들에 이를 되돌려보냅니다. 플라스크는 안전하게 데이터를 할당하여 간섭될수 없게합니다.
이제 사용자의 아이디는 세션에 저장됩니다, 이것은 다음연속 요청들에서 이용 가능합니다. 각 요청의 시작에서, 만약 사용자가 그들의 정보로 로그인 되어있다면, 로드되어야 하고 다른 뷰들이 이용가능하도록 만듭니다.
Bp.before_app_request()는 어떤 URL이 요청되는지에 상관없이 뷰 함수 전에 동작하는 함수를 등록합니다. load_logged_in_user는 사용자 아이디가 세션에 저장되어있는지 확인하고 데이터베이스에서 유저의 정보를 가져옵니다, 그러면서 이것을 요청의 길이 동안 지속되는 g.user에 저장합니다. 만약 그곳에 사용자 아이디가 없거나 아이디가 존재하지 않는다면, g.user는 None이 될 것입니다.
로그아웃
로그아웃 하기위해, 당신은 세션으로부터 사용자아이디를 제거할 필요가 있습니다. 그래야 load_logged_in_user는 차후연속 요청들에서 유저를 로드하지 않을 것입니다.
@bp.route(‘/logout’)
def logout():
session.clear()
return redirect(url_for(‘index’)
다른 뷰들에서의 인증의 필요
블로그 포스트를 만들고, 편집하고, 삭제하는 것은 사용자가 로그인 되어있을 필요가 있습니다. 데코레이터는 각각의 뷰에서 이의 적용이 됐는지 확인 할 수 있습니다.
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
이 데코레이터는 이것이 적용된 오리지널 뷰를 감싸는 새로운 뷰 함수를 리턴합니다. 새로운 함수는 사용자가 로드가 되어있는지 확인하고 그렇지 않다면 로그인 페이지로 리다이렉트합니다. 만약 사용자가 로드 된다면 오리지날 뷰는 호출되고 평범하게 진행됩니다. 당신은 블로그 뷰들을 작성할때 이 데코레이터를 사용할 것입니다.
엔드포인트와 URL들
Url_for()함수는 이름이나 아규먼트들에 기반한 뷰에 향하는 URL을 생성합니다. 뷰에 연관된 이름은 또한 엔드포인트라 불립니다, 그리고 디폴트로 이것은 뷰함수의 이름과 동일합니다.
예를 들어, 튜토이얼에서 이전에 앱 팩토리에 추가된 hello() 뷰는 ‘hello’라는 이름을 갖고 url_for(‘hello’)에 연결됩니다. 만약 이것이 당신이 나중에 보게 될 것 처럼 아규먼트를 갖는다면, 이것은 url_for(‘hello’, who=“world’)와 같은 방식으로 연결될 것입니다.
청사진을 사용할때, 청사진의 이름은 함수의 이름 앞에 붙여집니다, 따라서 당신이 위에 작성한 로그인 함수를 위한 엔드포인트는 ‘auth.login’입니다, 왜냐면 당신이 청사진 ‘auth’에 이를 추가했기 때문입니다.
템플릿에서 계속..
'플라스크' 카테고리의 다른 글
Define and Access the Database(데이터베이스 정의와 접근) (0) | 2021.08.18 |
---|