본문 바로가기
TIL _Today I Learned/2024.08

[DAY 22] Flask

by gamdong2 2024. 8. 9.
[천재교육] 프로젝트 기반 빅데이터 서비스 개발자 양성 과정 9기
학습일 : 2024.08.09

📕 학습 목록

  • Flask 이용하여 애플리케이션 제작

 

📗 기억할 내용

 

1) 코드 전문 뜯어보기

  • Flask를 이용하여 로그인/로그아웃, 게시판 페이지 제작
```python
# Flask 라이브러리에서 Flask 클래스와 관련된 여러 기능을 가져옴
from flask import Flask, jsonify, redirect, render_template, request, session, url_for

# db.py 파일에 있는 함수 호출 (데이터베이스 연결 함수)
from connection import db_connect

# [1. Flask 앱 초기화 및 설정]
app = Flask(__name__)  # Flask 애플리케이션 객체 생성
app.debug = True  # 디버그 모드 활성화: 서버 코드 수정 시 자동으로 반영됨
app.secret_key = "j0CZF9SS7N97xwajCEnmQxVrzT93Kvfn"  # 세션 관리용 비밀 키 설정

@app.route("/")  # 루트 경로("/")에 대한 요청 처리 함수 정의
def index():
    return render_template("index.html")  # index.html 템플릿을 렌더링하여 반환

# [2-1. 로그인 페이지 생성]
@app.route("/login", methods=["GET", "POST"])  # "/login" 경로에 GET과 POST 요청 허용
def login():
    SQL = """
        SELECT *
        FROM
            tb_user
        WHERE 1=1
            AND login_id = %s
            AND login_password = %s
    """  # 사용자를 인증하기 위한 SQL 쿼리
    error_message = None  # 오류 메시지 초기화
    if request.method == "POST":  # POST 요청이 들어올 경우 (로그인 시도)
        login_id = request.form["login_id"]  # 폼에서 입력된 login_id 가져오기
        login_password = request.form["login_password"]  # 폼에서 입력된 login_password 가져오기

        with db_connect() as conn:  # 데이터베이스 연결
            with conn.cursor() as cur:  # 데이터베이스 커서 생성
                cur.execute(SQL, [login_id, login_password])  # SQL 쿼리 실행
                user = cur.fetchone()  # 첫 번째 결과(한 명의 사용자)를 가져옴
                if user != None and len(user) > 0:  # 사용자가 존재하면
                    session["user"] = user  # 세션에 사용자 정보 저장
                    return redirect(url_for("index"))  # 메인 페이지로 리디렉션
                else:
                    error_message = "유저가 존재하지 않습니다."  # 사용자 없음 오류 메시지 설정

    return render_template("login.html", error_message=error_message)  # 로그인 페이지 렌더링

# [2-2. 로그아웃 기능 구현]
@app.route("/logout")  # "/logout" 경로에 대한 요청 처리 함수 정의
def logout():
    session.pop("user", None)  # 세션에서 "user" 정보를 삭제
    return redirect(url_for("index"))  # 메인 페이지로 리디렉션

# [3. 게시판 페이지 생성]
@app.route("/board")  # "/board" 경로에 대한 요청 처리 함수 정의
def view_board():
    SQL = """
        SELECT id, title, update_date
        FROM tb_board
        WHERE 1=1
        ORDER BY update_date DESC
    """  # 게시판 목록을 가져오기 위한 SQL 쿼리
    boards = []  # 게시판 목록을 저장할 리스트 초기화
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL)  # SQL 쿼리 실행
            boards = cur.fetchall()  # 모든 결과를 가져옴 (여러 게시물)
    return render_template("board.html", boards=boards)  # 게시판 페이지 렌더링

@app.route("/board/new", methods=["GET"])  # 새 게시물 작성 페이지 요청 (GET 방식)
def view_insert_board():
    return render_template("insert_board.html")  # 새 게시물 작성 페이지 렌더링

@app.route("/board/new", methods=["POST"])  # 새 게시물 작성 요청 (POST 방식)
def insert_board():
    SQL = """
        INSERT INTO tb_board(
            title, content, user_id
        )
        VALUES(
            %s, %s, %s
        )
    """  # 새 게시물을 삽입하기 위한 SQL 쿼리
    if not session.get('user'):  # 로그인 여부 확인
        return redirect(url_for("login"))  # 로그인 페이지로 리디렉션

    user_id = session["user"]["id"]  # 세션에서 사용자 ID 가져오기
    title = request.form["title"]  # 폼에서 입력된 제목 가져오기
    content = request.form["content"]  # 폼에서 입력된 내용 가져오기
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL, [title, content, user_id])  # SQL 쿼리 실행
            conn.commit()  # 데이터베이스에 변경사항 커밋
            return redirect(url_for("view_board"))  # 게시판 페이지로 리디렉션

# [4. 게시판 상세 페이지 생성]
@app.route("/board/<int:board_id>")  # "/board/<int:board_id>" 경로에 대한 요청 처리 함수 정의 (동적 라우팅)
def view_board_detail(board_id):
    SQL = """
        SELECT
            board.id,
            board.title,
            board.content,
            board.user_id,
            user.name,
            board.create_date,
            board.update_date
        FROM tb_board AS board
            INNER JOIN tb_user AS user ON board.user_id = user.id
        WHERE board.id = %s
    """  # 특정 게시물의 상세 정보를 가져오기 위한 SQL 쿼리
    board = {}  # 게시물 정보를 저장할 딕셔너리 초기화
    # [실습 : 댓글도 가져오기]
    # 방법1. 여기서 쿼리를 한번 더 실행하여 댓글 가져오기
    # 방법2. 별도의 API 라우트를 만들어 fetch()로 댓글 가져오기
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL, (board_id,))  # SQL 쿼리 실행
            board = cur.fetchone()  # 한 개의 게시물 상세 정보 가져오기
    return render_template("board_detail.html", board=board)  # 게시물 상세 페이지 렌더링

@app.route("/board/update/<int:board_id>", methods=["GET"])  # 게시물 수정 페이지 요청 (GET 방식)
def view_update_board(board_id):
    SQL = """
        SELECT
            id, title, content
        FROM
            tb_board
        WHERE
            id = %s
    """  # 수정할 게시물 정보를 가져오기 위한 SQL 쿼리
    board = {}  # 수정할 게시물 정보를 저장할 딕셔너리 초기화
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL, (board_id,))  # SQL 쿼리 실행
            board = cur.fetchone()  # 게시물 정보 가져오기
    return render_template("update_board.html", board=board)  # 수정 페이지 렌더링

@app.route("/board/update", methods=["POST"])  # 게시물 수정 요청 (POST 방식)
def update_board():
    SQL = """
        UPDATE tb_board SET
            title = %s,
            content = %s,
            update_date = NOW()
        WHERE id = %s
    """  # 게시물을 업데이트하기 위한 SQL 쿼리
    title = request.form["title"]  # 폼에서 입력된 제목 가져오기
    content = request.form["content"]  # 폼에서 입력된 내용 가져오기
    board_id = request.form["board_id"]  # 폼에서 입력된 게시물 ID 가져오기
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL, [title, content, board_id])  # SQL 쿼리 실행
            conn.commit()  # 데이터베이스에 변경사항 커밋
            return redirect(url_for("view_board_detail", board_id=board_id))  # 수정된 게시물의 상세 페이지로 리디렉션

# [5. 게시판 댓글 추가하기 - API 라우트]
@app.route("/api/comment/<int:board_id>")  # "/api/comment/<int:board_id>" 경로에 대한 요청 처리 함수 정의 (동적 라우팅)
def get_board_comments(board_id):
    SQL = """
        SELECT
            user.name, comment.id,
            comment.comment, comment.update_date
        FROM
            tb_board_comment comment
            INNER JOIN tb_user user
                ON comment.user_id = user.id
        WHERE comment.board_id = %s
    """  # 특정 게시물의 댓글들을 가져오기 위한 SQL 쿼리
    comments = []  # 댓글 목록을 저장할 리스트 초기화
    with db_connect() as conn:  # 데이터베이스 연결
        with conn.cursor() as cur:  # 데이터베이스 커서 생성
            cur.execute(SQL, (board_id,))  # SQL 쿼리 실행
            comments = cur.fetchall()  # 모든 댓글을

 

📘 트러블 슈팅

[문제]

  • 문제 내용
출력 과정에서 오류 발생
name = "홍길동"
age = 20
print("안녕하세요," + name "님, 당신의 나이는 " + age + "세입니다.")
{
	"name": "TypeError",
	"message": "can only concatenate str (not \"int\") to str",
	"stack": "---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 3
      1 name = \"홍길동\"
      2 age = 20
----> 3 print(\"안녕하세요,\" + name + \"님, 당신의 나이는 \" + age + \"세입니다.\")

TypeError: can only concatenate str (not \"int\") to str"
}
  • 문제 원인
1종류 이상의 자료형을 한 문장으로 출력하려면; 산술연산자(+)가 아닌 쉼표(,)로 연결

 

[해결]

  • 해결 방법
print("문자열", 변수, "문자열", 변수, "문자열") 의 형태로 출력
  • 해결 결과
name = "홍길동"
age = 20
print("안녕하세요, ", name, "님, 당신의 나이는 ", age, "세입니다.")
안녕하세요,  홍길동 님, 당신의 나이는  20 세입니다.

 

📙 내일 일정

  • 파이썬 프로그래밍(컨테이너 자료형, 조건문, ...) 학습

 

 

 

 

 

 

'TIL _Today I Learned > 2024.08' 카테고리의 다른 글

[DAY 24] Django 웹 애플리케이션 개발  (0) 2024.08.13
[DAY 23] Django 웹 애플리케이션 개발  (0) 2024.08.12
[DAY 21] Flask  (0) 2024.08.08
[DAY 20] SQL  (0) 2024.08.07
[DAY 19] API, DB, SQL  (0) 2024.08.06