책 '점프 투 플라스크'를 공부하면서 정리한 내용입니다.
출처 : https://wikidocs.net/book/4542
지금까지의 질문, 답변 모델 말고 회원 정보를 위한 모델이 필요하다.
pybo/models.py 필드를 바탕으로 User 모델을 작성
# --------------------------------- [edit] ---------------------------------- #
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
# --------------------------------------------------------------------------- #
(myproject) c:\projects\myproject>flask db migrate
(myproject) c:\projects\myproject>flask db upgrade
pybo/forms.py에 FlaskForm을 상속받아 UserCreateForm 클래스 생성
from flask_wtf import FlaskForm
# --------------------------------- [edit] ---------------------------------- #
from wtforms import StringField, TextAreaField, PasswordField
from wtforms.fields.html5 import EmailField
from wtforms.validators import DataRequired, Length, EqualTo, Email
# --------------------------------------------------------------------------- #
(... 생략 ...)
# --------------------------------- [edit] ---------------------------------- #
class UserCreateForm(FlaskForm):
username = StringField('사용자이름', validators=[DataRequired(), Length(min=3, max=25)])
password1 = PasswordField('비밀번호', validators=[
DataRequired(), EqualTo('password2', '비밀번호가 일치하지 않습니다')])
password2 = PasswordField('비밀번호확인', validators=[DataRequired()])
email = EmailField('이메일', [DataRequired(), Email()])
# --------------------------------------------------------------------------- #
username은 필수 항목이면서 길이를 제한해야 하므로 validators 옵션에 필수 항목으로 DataRequired()와 길이 조건 Length(min=3, max=25)를 추가했다.
email 필드에 설정한 이메일 검증을 사용하려면 email-validator가 필요하므로 반드시 설치
(myproject) c:\projects\myproject>pip install email_validator
회원가입용 화면을 만들기 위해 먼저 뷰를 만든다.
views/auth_views.py 파일 만들기
# --------------------------------- [edit] ---------------------------------- #
from flask import Blueprint, url_for, render_template, flash, request
from werkzeug.security import generate_password_hash
from werkzeug.utils import redirect
from pybo import db
from pybo.forms import UserCreateForm
from pybo.models import User
bp = Blueprint('auth', __name__, url_prefix='/auth')
@bp.route('/signup/', methods=('GET', 'POST'))
def signup():
form = UserCreateForm()
if request.method == 'POST' and form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if not user:
user = User(username=form.username.data,
password=generate_password_hash(form.password1.data),
email=form.email.data)
db.session.add(user)
db.session.commit()
return redirect(url_for('main.index'))
else:
flash('이미 존재하는 사용자입니다.')
return render_template('auth/signup.html', form=form)
# --------------------------------------------------------------------------- #
flash: 필드 자체 오류가 아닌 프로그램 논리 오류를 발생시키는 함수
generate_password_hash 함수 : 입력받은 비밀번호 값 그대로 저장하지 않고 암호화 하여 저장할 때 쓰는 함수. 암호화한 데이터는 복호화할 수 없다. 그래서 로그인할 때 입력받은 비밀번호는 바로 저장된 비밀번호가 아니라 암호화하여 저장된 비밀번호와 비교해야 한다.
__init__.py 파일에 auth 블루프린트 등록
def create_app():
(... 생략 ...)
# 블루프린트
# --------------------------------- [edit] ---------------------------------- #
from .views import main_views, question_views, answer_views, auth_views
# --------------------------------------------------------------------------- #
app.register_blueprint(main_views.bp)
app.register_blueprint(question_views.bp)
app.register_blueprint(answer_views.bp)
# --------------------------------- [edit] ---------------------------------- #
app.register_blueprint(auth_views.bp)
# --------------------------------------------------------------------------- #
(... 생략 ...)
return app
templates/auth/signup.html 작성
{% extends "base.html" %}
{% block content %}
<div class="container my-3">
<form method="post" class="post-form">
{{ form.csrf_token }}
{% include "form_errors.html" %}
<div class="form-group">
<label for="username">사용자 이름</label>
<input type="text" class="form-control" name="username" id="username"
value="{{ form.username.data or '' }}">
</div>
<div class="form-group">
<label for="password1">비밀번호</label>
<input type="password" class="form-control" name="password1" id="password1"
value="{{ form.password1.data or '' }}">
</div>
<div class="form-group">
<label for="password2">비밀번호 확인</label>
<input type="password" class="form-control" name="password2" id="password2"
value="{{ form.password2.data or '' }}">
</div>
<div class="form-group">
<label for="email">이메일</label>
<input type="text" class="form-control" name="email" id="email"
value="{{ form.email.data or '' }}">
</div>
<button type="submit" class="btn btn-primary">생성하기</button>
</form>
</div>
{% endblock %}
회원가입을 위한 ‘사용자 이름’, ‘비밀번호’, ‘비밀번호 확인’, ‘이메일’에 해당되는 input 엘리먼트를 추가. <생성하기> 버튼을 누르면 폼 데이터가 POST 방식으로 /auth/signup/ URL에 전송되도록. 회원가입을 할 때 발생하는 오류를 표시하도록 {% include "form_errors.html" %}를 사용.
<!-- 필드오류 -->
{% for field, errors in form.errors.items() %}
<div class="alert alert-danger" role="alert">
<strong>{{ form[field].label }}</strong>: {{ ', '.join(errors) }}
</div>
{% endfor %}
<!-- flash 오류 -->
{% for message in get_flashed_messages() %}
<div class="alert alert-danger" role="alert">
{{ message }}
</div>
{% endfor %}
navbar.html 수정
<li class="nav-item ">
<!-- ------------------------------ [edit] -------------------------------- -->
<a class="nav-link" href="{{ url_for('auth.signup') }}">계정생성</a>
<!-- ---------------------------------------------------------------------- -->
</li>
플라스크 셸에서 계정 정보 확인
(myproject) c:\projects\myproject>flask shell
>>> from pybo.models import User
>>> User.query.all()
>>> User.query.first().username