feat: Flask 애플리케이션 모듈화 및 웹 대시보드 구현
- Flask Blueprint 아키텍처로 전환 (dashboard, upload, backup, status) - app.py 681줄 95줄로 축소 (86% 감소) - HTML 템플릿 모듈화 (base.html + 기능별 templates) - CSS/JS 파일 분리 (common + 기능별 파일) - 대시보드 기능 추가 (통계, 주간 예보, 방문객 추이) - 파일 업로드 웹 인터페이스 구현 - 백업/복구 관리 UI 구현 - Docker 배포 환경 개선 - .gitignore 업데이트 (uploads, backups, cache 등)
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import sys, os
|
||||
import sys, os
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
import yaml
|
||||
@ -6,8 +6,10 @@ import requests
|
||||
from datetime import datetime, timedelta, date
|
||||
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
||||
from sqlalchemy import select
|
||||
import traceback
|
||||
|
||||
from conf import db, db_schema
|
||||
from requests_utils import make_requests_session
|
||||
|
||||
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "../conf/config.yaml")
|
||||
|
||||
@ -24,7 +26,9 @@ def fetch_data_range_chunks(start_dt, end_dt, chunk_days=10):
|
||||
yield current_start.strftime("%Y%m%d"), current_end.strftime("%Y%m%d")
|
||||
current_start = current_end + timedelta(days=1)
|
||||
|
||||
def fetch_asos_data(stn_id, start_dt, end_dt, service_key):
|
||||
def fetch_asos_data(stn_id, start_dt, end_dt, service_key, session=None):
|
||||
if session is None:
|
||||
session = make_requests_session()
|
||||
url = "http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList"
|
||||
|
||||
params = {
|
||||
@ -44,8 +48,9 @@ def fetch_asos_data(stn_id, start_dt, end_dt, service_key):
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
resp = None
|
||||
try:
|
||||
resp = requests.get(url, params=params, headers=headers, timeout=15)
|
||||
resp = session.get(url, params=params, headers=headers, timeout=20)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
items = data.get("response", {}).get("body", {}).get("items", {}).get("item", [])
|
||||
@ -57,7 +62,14 @@ def fetch_asos_data(stn_id, start_dt, end_dt, service_key):
|
||||
return items
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] API 요청 실패: {e}")
|
||||
body_preview = None
|
||||
try:
|
||||
if resp is not None:
|
||||
body_preview = resp.text[:1000]
|
||||
except Exception:
|
||||
body_preview = None
|
||||
print(f"[ERROR] ASOS API 요청 실패: {e} status={getattr(resp, 'status_code', 'n/a')} body_preview={body_preview}")
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
def save_items_to_db(items, conn, table, force_update=False, debug=False):
|
||||
@ -98,7 +110,7 @@ def save_items_to_db(items, conn, table, force_update=False, debug=False):
|
||||
data[key] = None
|
||||
|
||||
if debug:
|
||||
print(f"[DEBUG] {record_date} → DB 저장 시도: {data}")
|
||||
print(f"[DEBUG] {record_date} DB 저장 시도: {data}")
|
||||
continue
|
||||
|
||||
if force_update:
|
||||
@ -116,6 +128,7 @@ def save_items_to_db(items, conn, table, force_update=False, debug=False):
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 저장 실패: {e}")
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
def get_latest_date_from_db(conn, table):
|
||||
@ -149,6 +162,8 @@ def main():
|
||||
|
||||
chunk_days = 1000
|
||||
|
||||
session = make_requests_session()
|
||||
|
||||
with engine.begin() as conn:
|
||||
print(f"[INFO] DB 저장 최종 일자 점검")
|
||||
latest_date = get_latest_date_from_db(conn, table)
|
||||
@ -170,7 +185,7 @@ def main():
|
||||
for stn_id in stn_ids:
|
||||
for chunk_start, chunk_end in fetch_data_range_chunks(start_dt, end_dt, chunk_days):
|
||||
print(f"[INFO] 지점 {stn_id} 데이터 요청 중: {chunk_start} ~ {chunk_end}")
|
||||
items = fetch_asos_data(stn_id, chunk_start, chunk_end, service_key)
|
||||
items = fetch_asos_data(stn_id, chunk_start, chunk_end, service_key, session=session)
|
||||
if items:
|
||||
save_items_to_db(items, conn, table, force_update, debug)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user