Backend/Flask

Flask 기초 I - Blueprint, Jinja2, 로그인 구현, 로깅

yxemsy 2022. 2. 7. 23:56

1) Blueprint와 Jinja Template

 

  • Blueprint
Flask의 기능이 늘어날수록, 코드의 양이 증가한다.
이때, Blueprint를 사용해 길어진 코드를 모듈화해주어 수정 개발과 유지보수에 용이하게 코드를 관리한다.

 

아래 코드는 Blueprint를 사용하지 않았을 때의 코드이다. 

#app.py

rom flask import Flask, jsonify 
app = Flask(__name__)

@app.route("/", methods=['GET'])
def home_route():
	return jsonfiy('home')
    
@app.route("/first",methods=['GET'])
def first_route():
	return jsonify('first page')

기본 url인 "/"을 제외하고 "/first" url 라우터를 아래 코드와 같이 모듈화 할 수 있다.

 

#first_api.py

from flask import Blueprint, jsonify # blueprint를 import
bp = Blueprint('bp',__name__)  # app 대신 새로운 이름으로 쓸 bp를 작성해야한다.

@bp.route('/first',methods=['GET']) ## 여기서도 @app 대신 @bp를 사용해야한다.
def first_route():
	return jsonify('first page')

위 처럼 기능별로 파일을 만들어 블루프린터로 작성할 수 있다. 그리고 app.py에서 아래와 같이 import 시켜주면 된다.

 

#app.py

from flask import Flask 
from first_api import bp # from 파일명 import 라우터명

app = Flask(__name__)
app.register_blueprint(bp) # 사용할 블루프린터 파일명을 괄호 안에 작성한다.

if__name__ == '__main__':
	app.run(debug=True)

위 예시 코드는 기능이 없어 간단해서 블루프린터가 유용하진 않지만,

많은 기능들을 구현하게 될 때 효과적이다.

 


  • Jinja2
Python에서 가장 많이 사용되는 템플릿이다.
서버에서 받아온 데이터를 효과적으로 보여주고, 간략한 표현으로 데이터를 가공한다.

아래와 같이 app.py는 html 파일에서 데이터를 받아올 수 있다.

# app.py

@app.route("/")
def name():
	return render_template('index.html' ,   # 데이터를 출력할 html 파일명
    				data = 'hayan' # 출력하고 싶은 데이터에 값을 대입
                    )  
                  
@app.rounte("/")
def list():
	num_list = [1, 2, 3, 4, 5]  # 숫자 리스트 
    	return render_template('index.html',
        			list = num_list   # list라는 변수에 num_list 대입
                                )
                                
@app.rounte("/")
def dict():
	user = ['name': 'hayan']  # 키가 name이고 값이 hayan인 딕셔너리
    	return render_template('index.html',
        			dict = user   # dict 변수에 딕셔너리 대입
                                )

name 함수는 단일 데이터, list함수는 리스트, dict함수는 딕셔너리 데이터를 jinja 템플릿에서 받아온다.

아래 html 파일에서 받아올 것이다.

 

# index.html

<html>
   	<head>
		<title> jinja example </title>
	</head>
	<body>
		{{ data }}  # 두 쌍의 중괄호 안에 data 변수를 작성. app.py로 data 값을 넘겨준다.
        
        	{{ list }}  # 리스트 출력
        	{% for num in list %}  # for문 돌려서 list의 숫자 값 하나씩 출력
        	  {{ num }}
        	{% endfor %} # for문 사용 후 반드시 endfor로 닫아주어야 한다.
        
        	{{ dict.get('name') }} # dict에서 키 값이 name인 value 출력. 즉 hayan 출력
	</body>
</html>

위의 코드처럼 jinja2 템플릿은 파이썬의 문법을 사용하여 간편하게 작성이 가능하다.

 


2) CRUD 설계 및 제작

이전 포스팅에서도 간단히 설명했지만, Create, Read, Update, Delete의 약자로
데이터의 생성, 조회, 수정, 삭제를 의미한다.

 

CRUD HTTP Method DB 명령어
Create POST INSERT
Read GET SELECT
Update PUT, PATCH UPDATE
Delete DELETE DELETE

 


3) Authentication

Authentication이란 인증이다. Authorization인 권한이랑은 다른 개념이다.
사용자가 누구인지 확인하는 절차로, 회원가입하고 로그인하는 과정을 의미한다.

 

 


4) 로그인 기능 구현

로그인 기능을 구현하려면 다음과 같은 개념을 알아야한다.

 

(1) 쿠키: 클라이언트에 저장되는 키/값이 들어 있는 데이터로,
사용자가 따로 요청하지 않아도 요청시에 자동으로 서버에 전송한다.

(2) 세션: 쿠키를 기반으로 하지만 서버에서 관리하는 데이터로,
클라이언트에 고유 ID를 부여하며 보안이 쿠키보다 우수하다.

 

다음과 같이 간단하게 로그인 기능을 구현할 수 있다.

user_id = request.form['user_id'] # request로 받아온 로그인 정보를 id 변수에 저장
user_pw = request.form['user_pw'] # pw 변수에 저장한다.
user = {'user_id': 'hayan', 'user_pw': '1234'}

if user is not None: 
    if user_id == user['user_id'] and user_pw == user['user_pw']: 
    # 데이터베이스에서 user_id와 같은 데이터가 있는지 찾아온다.
    # 입력된 user_pw와 저장된 패스워드가 같은지 체크한다.
    	session['login'] = user.id # session을 login으로 채워주고 user.id 값을 넘긴다.
        return jsonify({"result":"success"})
    else:
    	return jsonify({"result":"fail"})

실제 데이터베이스는 아니고 딕셔너리를 주어 구현한 코드이다.

session[] 안의 값은 'login'이 아니어도 되고 본인이 값을 지정하면 된다.

 

session['login'] = None

만약 로그아웃을 하고싶다면 로그인 세션을 비워주면 완료된다.

 


5) 로깅

프로그램이 작동할 때 발생하는 이벤트를 추적하는 행위이다.
프로그램의 문제를 파악하고 유지보수하는 데 사용되며, 에러 추적이 가능하다.

 

  • 로깅의 level

DEBUG < INFO < WARNING < ERROR < CRITICAL

오른쪽으로 갈 수록 중대한 문제이다.

기본 로거 레벨 세팅은 WARNING 이어서 설정 없이 INFO와 DEBUG 출력이 불가능하다.

DEBUG는 상세한 정보, INFO는 일반 정보를 뜻한다.

 

다음과 같이 설정하면  DEBUG와 INFO도 출력할 수 있다.

from flask import Flask
app = Flask(__name__) 

if__name__ == '__main__': 
    app.logger.info("test") 
    app.logger.debug("debug test") 
    app.logger.error("error test") 
    app.run()