flask는 django와 더불어 python을 기반으로 작동하는 웹 프레임워크다. 필자의 경우 웹 개발 공부를 django로 시작했기 때문에, 이번에 flask를 사용해보는 과정에서 자연스레 django와의 차이점이 궁금해졌다.
첫 번째 특징은 가볍고 단순하다는 점이다.
ORM 기능이 제공되지 않는다.
종합하면 단순한 REST API 서버를 만들기에는 Flask가 django보다 효율적이라고 할 수 있다.
Micro Framework??
웹 개발에 필요한 최소한의 기능만을 갖춘 프레임워크. ORM 기능, 유효성 검사 기능, 인증·인가 기능 등을 제공하지 않는 것이 일반적이며, 주로 application의 API를 설계하는 데 사용된다.
설치 및 불러오기
pip install flask
from flask import Flask, jsonify, request
app.config['JSON_AS_ASCII'] = False
추가if request.method == 'GET':
name = request.args.get('key', "None")
Flask 객체 생성 및 할당
app = Flask(__name__)
객체를 이용해 라우팅 경로 설정
@app.route('/port 번호 뒤에 이어질 url 경로')
라우팅 경로에 대한 실행 함수 작성
@app.route("/"
def hello():
result = 'Hello world!'
return result
실행할 서버 IP와 포트 입력
if __name__ == "__main__":
app.run(debug=True, host='localhost', port=8000)
서버 열기
python 파일명.py
from datetime import datetime
from flask import Flask, jsonify, request
from flask.signals import appcontext_tearing_down
from directquery import DirectQuery
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
@app.route('/subway')
def get():
if request.method == 'GET':
name = request.args.get('station', None)
direct_query = DirectQuery()
if not name:
return jsonify({"message" : "NO DATA"})
data_list = direct_query.execute_query(
f"SELECT sub_lines.name AS line, stations.*, names.name AS name, station_time_info.*, names.name as name2 FROM \
subway_lines AS sub_lines, subway_stations AS stations, station_names AS names, \
station_time_information AS station_time_info WHERE sub_lines.id = stations.subway_line_id AND \
stations.station_id = station_time_info.station_id AND names.station_id = stations.station_id \
AND (names.name LIKE '%{name}%' OR sub_lines.name LIKE '%{name}%' OR stations.station_code = \
'{name}');"
)
if not data_list:
return jsonify({"message" : "NO DATA"})
result = [{
'호선' : data[0],
'역 이름(한글)' : data[6],
'역 외부 코드' : data[4],
'환승역 여부' : 'Y' if data[5] == 1 else 'N',
'역 시간 정보' : [{
'상/하행선' : '상행선' if data[8] == True else '하행선',
'요일 구분' : '평일' if data[9] == 1 else '토요일' if data[9] == 2 else '휴일',
'첫차 출발 시간' : (data[11] + datetime.min).time().strftime('%H시 %M분'),
'첫차 도착역명' : direct_query.execute_query(f"SELECT names.name FROM station_names AS names JOIN station_time_information AS time_info ON names.station_id = '{data[12]}' LIMIT 2;")[1][0] if data[12] != '0000' else None,
'막차 출발 시간' : (data[13] + datetime.min).time().strftime('%H시 %M분'),
'막차 도착역명' : direct_query.execute_query(f"SELECT names.name FROM station_names AS names JOIN station_time_information AS time_info ON names.station_id = '{data[14]}' LIMIT 2;")[1][0] if data[14] != '0000' else None,
}]} for data in data_list]
return jsonify({'result': result})
if __name__ == "__main__":
app.run(debug=True, host='localhost', port=8000)
import pymysql
import db_config
class DirectQuery():
def execute_query(self, sql):
conn = pymysql.connect(
host ='localhost', user=db_config.DATABASES['USER'],
password =db_config.DATABASES['PASSWORD'], db=db_config.DATABASES['NAME'],
charset ='utf8mb4', port=3306
)
try:
with conn.cursor() as cursor:
cursor.execute(sql)
data = [x for x in cursor.fetchall()] if cursor else None
conn.commit()
conn.close()
except:
data = 'sql error'
return data
directquery.py에서 db 데이터를 가져올 때, 튜플 형태가 아닌 딕셔너리 형태로 가져오려면 pymysql.connect()
내부에 cursorclass=cursors.DictCursor
를 추가해주면 된다.
conn = pymysql.connect(
host ='localhost', user=db_config.DATABASES['USER'],
password =db_config.DATABASES['PASSWORD'], db=db_config.DATABASES['NAME'],
charset ='utf8mb4', port=3306, cursorclass=cursors.DictCursor
)
SQL 쿼리문을 통해 db 데이터를 불러오는 횟수가 증가할수록 서버에 부담을 주게 된다. 그러므로 하나의 API에서 SQL쿼리문 사용을 한 번으로 줄이는 것이 바람직하다.
if __name__ == "__main__":
이 사용될 경우, 상대경로가 아닌 절대경로를 사용하여 외부 모듈을 import해야 한다.
Datetime module
from datetime import datetime
로 모듈을 import하면 datetime을 두 번 입력할 필요 없이 메소드 실행 가능 ex)datetime.now()
Mysql의 필드 타입인 time은 datetime.timedelta() 형식으로 입력된 시간을 return한다.
datetime.timedelta()
형식을 일반적인 시간으로 표시하려면 다음과 같은 명령어를 사용하자
(datetime.timedelta 객체 + datetime.min).time().strftime()