HAZEL

[ Flask 02. ] MVC 패턴으로 웹 만들기, 모델 , 뷰, 컨트롤러 만들기, Flask-WTF , CSRF 본문

PROGRAMMING/Flask

[ Flask 02. ] MVC 패턴으로 웹 만들기, 모델 , 뷰, 컨트롤러 만들기, Flask-WTF , CSRF

Rmsid01 2021. 8. 17. 19:25
  • FastCampus 파이썬 웹 개발 올인원 패키지 Online. 강의 중, Framework Flask 기초 part 를 듣고 정리한 글입니다.

1. 모델 만들기

컨트롤러 부분과 모델부분의 코드를 분리 시켜주어야 한다. 

컨트롤러 부분에서 from models import db 를 하면, models 에서 만들어준 db를 불러 올 수 있다. 

 

app.py

import os
from flask import Flask
from flask import render_template
from models import db


app = Flask(__name__)

@app.route('/register')
def register():
    return render_template('register.html')

@app.route('/')
def hello():
    return render_template('hello.html')

# 파이썬 명령어로 실행할 수 있도록 아레처럼 작성
if __name__ == '__main__':
    basedir = os.path.abspath(os.path.dirname(__file__))  # 현재 있는 파일의 dir
    dbfile = os.path.join(basedir, 'db.sqlite')

    # app관련 설정
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + dbfile
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    db.init_app(app) # 다양한 app의 설정값들을 초기화 해줌
    db.app = app # app 을 명시적으로 넣어줄 수 있음.
    db.create_all() # 데이터 베이스 생성

    app.run(host='127.0.0.1', port=5000, debug=True)

 

models.py

# 모델에 관련된 코드

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Student(db.Model):
    __tablename__ = 'Student'
    id = db.Column(db.Integer, primary_key=True)
    password = db.Column(db.String(64))
    studentid = db.Column(db.String(32))
    studentname = db.Column(db.String(8))

 

2. 뷰 만들기

templates 에 html을 이용해서 원하는 페이지를 만들어준다.

그 후, app.py 에 원하는 html 로 render 해주면 된다.

@app.route('/register')
def register():
    return render_template('register.html')

@app.route('/')
def hello():
    return render_template('hello.html')

 

3. 컨트롤러 만들기

: 컨트롤러 개발 즉, 비즈니스 로직을 넣어주면 된다.

 

1 ) 화면에 GET , POST 메소드를 설정해주기

: get 요청은 단순히 값을 보여주는것이고 post 요청은 데이터를 가지고 오는 요청이다.
  따라서, get과 post 인 경우를 구분해서 코드를 작성해야한다.
: 메서드가 기본적으로 get 만 되어있기 때문에, methods=['GET', 'POST'] 로 post도 추가해준다.

@app.route('/register', methods=['GET', 'POST'])
def register():
    return render_template('register.html')

그렇담, html 파일에서 화면만 볼때는 'GET' 이 뜨고, 등록버튼 누르면 'POST' 가 뜨는것을 터미널에서 확인 할 수 있다. 

 

2 ) GET 과  POST 코드 따로 작성해주기

from flask import request # request 를 이용해서 요청정보를 확인 할 수있다.
from flask import redirect

app = Flask(__name__)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html')
    else:
        # 회원 정보 생성
        return redirect('/')

 

3 ) Post 에 값이 잘 들어왔는지 확인하기

: html 에 설정한 값을 flask request.form.get 에 넣어주면, 그 값이 잘 들어왔는지 확인이 가능하다. 

 

register.html

<div class="form-group">
  <label for="studentid">학생 id</label>
  <input type="text" class="form-control" id="studentid" placeholder="학생 id" name="studentid" />
</div>

 

app.py

import os
from flask import Flask
from flask import render_template
from models import db
from flask import request # request 를 이용해서 요청정보를 확인 할 수있다.
from flask import redirect

from models import Student

app = Flask(__name__)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html')
    else:
        # 입력받은 값을 먼저 확인 request.form.get 을 이용해서, 값을 가져올 수 있다.
        studentid = request.form.get('studentid')
        studentname = request.form.get('studentname')
        password = request.form.get('password')
        re_password = request.form.get('re-password')
        print(studentid)

        return redirect('/')

 

4 ) 비즈니스 로직 넣기

app.py

# 데이터가 올바르게 들어왔는지 검증
# 1 ) 데이터가 다들어 왔는지
if not (studentid and studentname and password and re_password):
	return render_template('register.html')

# 2 ) 비밀번호 두개가 일치하는지
if password != re_password:
	return render_template('register.html')

 

5 ) 데이터를 db에 넣고 확인

app.py

# 회원 정보 생성 - 1) 클래스 만들기
student_info = Student()
student_info.studentid = studentid
student_info.studentname = studentname
student_info.password = password

# 2) 정보를 넣기
db.session.add(student_info) # db에 넣겠다! 라는 의미
# 사실은, 여기서 commit을 안해도, app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 로 인해 커밋은 되지만
#  의도적으로 커밋을 하는 것은 중요하다고 함
db.session.commit()

 

터미널에서 아래의 코드 실행

(flask_project) $ sqlite3 db.sqlite
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
sqlite> .tables
Student
sqlite> select * from Student;
1|4545|test_student|테스트

 

* 전체 코드

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html', form=form)
    else:
        studentid = request.form.get('studentid')
        studentname = request.form.get('studentname')
        password = request.form.get('password')
        re_password = request.form.get('re-password')
        print(studentid)

        if not (studentid and studentname and password and re_password):
            return render_template('register.html')

        if password != re_password:
            return render_template('register.html')

        student_info = Student()
        student_info.studentid = studentid
        student_info.studentname = studentname
        student_info.password = password

        db.session.add(student_info) # db에 넣겠다! 라는 의미
        db.session.commit()

    return redirect('/')

 

4. Flask-WTF 

1 ) Flask-WTF 설치 및 form 만들기

: 쉽게 유효성 검사를 할 수 있도록 함.

(flask_project) $ pip install Flask-WTF

 

- Form 만들기

forms.py

: form py 안에는 값들이 유효한지에 대한 검사파일을 넣어줄 수 있다.

wtforms.validatiors 안에 다양한 유효성 검사 라이브러리가 있다.

EqualTo : () 에 들어가 있는 것과 같은 것인지 확인하는 검사

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms.validators import DataRequired, EqualTo

class RegisterForm(FlaskForm):
    # 내가 입력받고자 하는 폼을 여기에 넣어주면 됨
    studentid = StringField('studentid', validators=[DataRequired()])
    studentname = StringField('studentname', validators=[DataRequired()])
    password = PasswordField('password', validators=[DataRequired(), EqualTo('repassword')])
    repassword = PasswordField('repassword', validators=[DataRequired()])

 

app.py

: form 안에서 validate_on_submit을 통해서 post 요청이 되었고, 유효성 검사가 잘 되었는지 한번에 확인 가능하다.
: 값이 정상적인지, 모든 값들을 확인하는 기존의 코드 모두 필요없어지게 된다. 아래의 코드만 남게 된다. 

from forms import RegisterForm

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    # form 안에서 validate_on_submit을 통해서 post 요청이 되었고, 유효성 검사가 잘 되었는지 한번에 확인 가능
    # 값이 정상적인지, 모든 값들을 확인하는 코드모두 필요없어짐
    if form.validate_on_submit():
        student_info = Student()
        student_info.studentid = form.data.get('studentid')
        student_info.studentname = form.data.get('studentname')
        student_info.password = form.data.get('password')

        db.session.add(student_info) # db에 넣겠다! 라는 의미
        db.session.commit()
        print('Success')

        return redirect('/')
    return render_template('register.html', form=form)

 

2 ) CSRF 설정

:  CSRF 란, 사이트 간 요청 위조 를 의미하는데 이를 방지하기 위해서 CSRFProtect를 이용한다.

 

CSRF 를 방지하기 위해서, form 안에 해쉬코드를 넣어주는 기능을 사용 

보통은 프레임워크 등 이미 구현된 것을 사용해서 한다. 

 

app.py

from flask_wtf.csrf import CSRFProtect

if __name__ == '__main__':
    # app관련 설정
    app.config['SECRET_KEY'] = '3fjwljflejflwjflejfef' # 원래는 복잡하게 해야함 지금은 임의적으로

    csrf = CSRFProtect()
    csrf.init_app(app)

 

register.html

<form method="POST">
	{{ form.csrf_token }}

 

- csrf_token 값을 받는 것을 확인 할 수있다. 

 

3 ) 유효성 코드를 위한 template 의 html 코드 수정하기.

: 뷰에서 보이는 모습은 그대로이나, 유효성 검사등을 알아서 해주게 된다.

 

- before

<div class="form-group">
  <label for="studentid">학생 id</label>
  <input type="text" class="form-control" id="studentid" placeholder="학생 id" name="studentid" />
</div>

 

- after

<div class="form-group">
  {{ form.studentid.label("아이디") }}
  {{ form.studentid(class="form-control", placeholder="아이디")}}
</div>

 

'PROGRAMMING > Flask' 카테고리의 다른 글

[ Flask 01. ] Flask실행, MVC, Model, SQLAlchemy, Jinja2  (0) 2021.08.16