3. 사용자 등록 기능 - 3.1. 계정 정보 정의
웹 서비스에 추가할 가장 첫 기능으로 사용자로부터 계정 정보를 받아서 서버에 저장하는 '사용자 등록' 기능을 구현해보고자 한다. 이 기능을 가장 먼저 다루는 첫째 이유는 웹을 통한 데이터 입력을 실습해 볼 수 있고, 둘째 이유는 입력받은 데이터의 보관, 즉, 데이터베이스를 다루는 방법을 알 수 있기 때문이다.
웹 서비스의 가장 기본적인 기능이 데이터를 입력 받고 → 관리(보관)하고 → 필요한 데이터를 제공하는 것이기 때문에 '사용자 등록 기능' 구현을 통해 데이터 입력과 관리라는 웹 서비스의 앞의 두 가지 요소를 배울 수 있다.
사용자 등록(=계정 생성)의 전제는 사용자 인증(예, 로그인, login)이다. 따라서 계정 생성을 위한 데이터를 입력받을 때 부터 로그인이라는 사용자 인증 과정에 대해 고려하지 않을 수 없다. 이를 위해 Flask login 이라는 오픈소스 패키지의 도움을 받을 것이다. Flask login은 서버에 등록된 사용자 데이터를 이용하여 사용자 인증(로그인)을 돕는 플라스크 패키지이다.
앞의 포스팅 '2. 모델/폼 - 뷰 - 로직'에서 살펴보았던 바와 같이 가장 먼저 데이터 입력과 보관(관리)을 위한 데이터 폼(form)과 모델(model) 정의에서부터 웹 서비스 기능 구현을 시작할 것이다. 한 과정씩 차분히 살펴보자.
새로 프로젝트를 하나 생성하고(02_user_registration) 아래와 같이 첫 포스팅 '1. 웹 서비스의 기본 틀'에서 만들어 두었던 웹 서비스 뼈대(01_flask_blog_template) 프로젝트 내용을 복사해서 가져온다.
그리고 파이참의 File → Settings → Project Interpreter → pip으로 진입한 후 Flask-Login 패키지를 검색하고 설치한다.
appmain 패키지 아래에 user 패키지 디렉토리를 하나 만들자. 이 user 패키지에 사용자 등록, 인증(로그인), 사용자 정보관리 등 사용자 계정을 관리하는 기능들을 모아 둘 것이다.
데이터베이스(DB)에 사용자 정보를 저장하기 위해 데이터 모델(model)을 먼저 정의한다.
▶ appmain/user/models.py
#### 사용자 데이터는 DB에 저장되고 관리된다.
#### 이를 위해 DB를 클래스 형태로 연동할 수있게 도와주는 SQLAlchemy 객체인 db를 불러온다.
#### 생성할 계정의 관리를 위해 Flask-Login의 loginManager 객체도 가져온다.
#### SQLAlchemy db 객체와 loginManager 객체는 상위 패키지인 appmain에서 생성할 것이다.
from appmain import db, loginManager
#### 플라스크 프레임워크가 사용자 관리를 위해 flask_login 패키지를 사용하기 위해서는 서버에 저장될
#### 사용자 데이터에 flask_login이 필요로 하는 변수 및 함수를 포함시킬 필요가 있다.
#### 이를 위해 UserMixin 클래스를 가져온다.
from flask_login import UserMixin
#### Flask-Login의 LoginManager의 load_user 함수를 구현(implement)해 주어야 한다.
#### 왜냐하면 데이터 모델에 따라 데이터를 가져오는 방법을 알려주어야 하기 때문이다.
#### DB에 userId를 인자(argument)로 데이터를 요청(query)하고 가져오는(get) 동작이 그 내용이다.
@loginManager.user_loader
def load_user(userId):
return Userdata.query.get(int(userId))
#### 계정 데이터 모델을 클래스로 정의한다. SQLAlchemy와의 연동을 위해 db객체로부터 Model 클래스를 상속받고,
#### 다시 flask_login 패키지와의 연동을 위해 UserMixin 클래스를 포함시킨다.
class Userdata(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True, nullable=False)
email = db.Column(db.String(60), unique=True, nullable=False)
picture = db.Column(db.String(20), nullable=False, default="default.png")
password = db.Column(db.String(60), nullable=False)
데이터 모델 클래스 작성방법은 '파이썬 웹 프로그래밍 기본' 편 '7. 정보관리 - 7.2.파이썬으로 DB 사용하기' 포스팅에서 자세히 설명하였다.
이제 사용자 데이터를 받아오기 위한 폼(form)을 정의해보자. 폼은 '어떤 정보를 어떤 형태로 받겠다'라고 선언하는 것이다. 사용자 데이터 입력과 입력한 데이터 처리(검증 등)를 위해 flask_wtf라는 패키지를 사용할 것이다(). 다시 File → Settings → Project Interpreter → pip으로 진입한 후 Flask-WTF로 패키지를 검색하고 설치한다.
Flask-WTF 패키지를 설치하면 WTForms 패키지도 함께 설치될것이다.
Flask-WTF는 'Flask What The Form'을 줄인 이름이다.
아래와 같이 user 패키지 안에 forms.py 파일을 생성하고 폼을 정의하자.
▶ appmain/user/forms.py
#### 필요한 외부 패키지들을 가져온다.
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from flask_wtf.file import FileField, FileAllowed
#### 앞서 정의한 계정 정보 모델을 가져온다.
from appmain.user.models import Userdata
#### FlaskForm을 상속받은 계정정보 입력 폼 클래스를 정의한다.
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
picture = FileField('Profile picture', validators=[FileAllowed(['jpg', 'png'])])
submit = SubmitField('Sign Up')
#### 같은 이름을 사용하는 계정이 있는지 검증(validation)하는 메서드를 정의한다.
def validate_username(self, username):
user = Userdata.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is already taken. Please choose a different username.')
#### 같은 이메일 주소를 사용하는 계정이 있는지 검증하는 메서드를 정의한다.
def validate_email(self, email):
email = Userdata.query.filter_by(email=email.data).first()
if email:
raise ValidationError('That email is already taken. Please choose a different email address.')
계정 정보 입력 클래스 RegistrationForm에 쓰인 요소들을 정리하면 아래와 같다.
FlaskForm | 입력 데이터의 전송 등과 같이 기본적인 기능을 제공하는 클래스이다. |
StringField | 문자열 입력 창에 사용되는 데이터 형식을 정의한다. |
PasswordField | 암호 입력 창에 사용되는 데이터 형식을 정의한다. |
SubmitField | 제출(submit) 버튼을 정의한다. |
아래는 validators에 사용된 요소들이다. validators 리스트에 지정된 조건들은 입력된 요소들이 올바로 입력되었는지 검증하는데 사용된다.
DataRequired | 입력된 데이터가 있는지 검증한다. |
Length | 입력된 데이터 길이가 정해진 조건을 만족하는지 검증한다. |
EqualTo | 입력한 데이터가 어떤 다른 데이터와 같은지 검증한다. |
입력한 데이터가 이메일 형식에 맞는지 검증한다. |
정보 입력 폼 클래스에 사용자가 폼에 입력한 데이터가 제대로 입력되었는지 검증하는 클래스 메서드(클래스 함수)를 정의할 수 있다. 이들 검증 함수들의 정식 명칭은 in-line validator이고 함수 이름으로 접두어(prefix) ‘validate_’를 붙이고, 이어서 검증을 수행할 입력 데이터 이름을 붙인다. 예를 들어 validate_username은 username 입력 값을 검증한다는 뜻이다.
앞서 입력 변수 정의에서 지정한 validators들과 비교하여 프로그래머가 원하는 내용을 직접 구현할 수 있기 때문에 좀 더 다양하고 세밀한 검사가 가능하다. 이들 in-line validator들은 프로그래머가 명시적으로 호출하지 않아도 사용자 입력을 받을 때 자동으로 수행된다.
여기까지 다루려는 데이터를 정의하는 '모델/폼 정의' 과정을 살펴보았다. 이어지는 포스팅들에서 '뷰(view)'와 '로직(logic)'을 추가해서 계정 생성 기능을 완성시켜보자.
■