Study/Python

[Python] DB를 연결하여 todolist 만들기

토기발 2023. 7. 30. 18:06

파이썬 공부를 시작하고 이론들을 공부하다가 배운 것들을 복습하고 싶기도 하고, 빨리 능숙해져서 웹사이트를 만들고 싶기도 해서 간단한 프로그램을 만들기로 했다.

간단한 프로그램 하면 투두리스트! 라고 생각해서 검색해보니 대부분 Django로 만들고 있어서 아직 내 수준으로는 어려울 것 같았다.

그래서 나는 DB를 연결해서 쿼리를 통해 동작하고, 콘솔에 결과가 표시되는 아주 간단한 투두리스트를 만들었다.

 

 

먼저 DB와 테이블을 생성한다.

 

CREATE DATABASE todos;

USE todos;

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    description VARCHAR(255),
    done BOOLEAN DEFAULT FALSE
);

그런데 이렇게 테이블을 등록한 후 쿼리를 실행하면

Error : (1366, "Incorrect string value: '\\xED\\x8C\\x8C\\xEC\\x9D\\xB4...' for column `todos`.`tasks`.`description` at row 1")

에러가 났다.

mariaDB와 파이썬의 인코딩방법이 달라서 생기는 문제라고 한다.

그래서 아래 쿼리를 추가해주면 제대로 동작한다.

ALTER TABLE tasks CONVERT TO CHARSET utf8;

 

이제 .py파일을 만들고 DB를 연결한다.

 

import pymysql

connection = pymysql.connect(
    host = 'localhost',
    user= 'root',
    password = '비밀번호',
    db= 'todos'
)

pymysql 은 Python에서 MySQL 데이터베이스와 상호작용하기 위한 라이브러리이다.

MariaDB와도 연동되기 때문에 사용하기로 했다.

 

connection = pymysql.connect()

괄호 안에 DB정보를 입력해주면 된다.

나는 유저명이 root라서 root로, db는 아까 만들었던 todos로 기입했다.

 

def add_todo(description):
    try:
        with connection.cursor() as cursor:
            sql = "INSERT INTO tasks (description) VALUES (%s);"
            cursor.execute(sql, (description,))
            connection.commit()

    except pymysql.Error as e:
        print(f"Error : {e}")
        connection.rollback()

할 일을 추가하는 함수이다.

 

add_todo()에 description을 매개변수로 받았다.

with connection.cursor() as cursor: 구문은 pymysql 라이브러리를 사용하여 데이터베이스와 상호작용할 때 많이 쓰인다. 이를 통해 cursor 객체를 생성하고, 데이터베이스와의 상호작용을 보다 편리하게 처리할 수 있다.

cursor는 데이터베이스와 상호작용할 때 쿼리를 실행하고 결과를 가져오는 역할을 한다.

 

sql = "INSERT INTO tasks (description) VALUES (%s);"

쿼리를 사용해서 테이블에 데이터를 집어넣는다.

cursor.execute() 메서드는 SQL 쿼리를 실행할 때 쿼리에 전달할 파라미터(이 쿼리에서는 (description))를 튜플 형태로 전달하여 해당 값을 SQL 쿼리에 동적으로 삽입한다. 

삽입이 끝나면 commit 해준다.

 

try -except 문으로 예외를 try에서 잡아서 예외가 발생한다면 try에서 중단하고, except블록으로 넘어간다.

as e를 통해 예외 객체를 e라는 변수에 할당한다. 

이 코드에서는 에러를 프린트하고 rollback한다.

 

이제 이 함수를 호출하기 위한 코드를 작성한다.

 

todo = input("할 일을 입력하세요 : ")
add_todo(todo)

input을 통해 사용자의 입력값을 받아서 todo라는 변수에 사용자가 입력한 할 일을 저장한 후, add_todo(todo) 함수를 호출하여 할 일을 데이터베이스에 추가한다.

 

이제 할 일 리스트(투두리스트)를 조회하는 함수를 만들어보자.

 

 

def view_todos():
    try:
        with connection.cursor() as cursor:
            sql = "SELECT * FROM tasks;"
            cursor.execute(sql)
            result = cursor.fetchall()
            if not result:
                print("할 일이 없습니다.")
            else:
                print("할 일 목록 : ")
                for row in result:
                    status = "완료" if row[2] else "미완료" 
                    print(f"{row[0]}. {row[1]} ({status})")
    except pymysql.Error as e:
        print(f"Error: {e}")

cursor.fetchall() 은 SELECT 쿼리의 결과를 모두 가져오는 메서드이다.

테이블에 아무 데이터도 없다면 할 일이 없다는 문구를 출력하고, 데이터가 있을 경우 for문을 돌려서 할 일의 상태를 확인하고 정보를 출력한다.

row[0] 은 그 행의 0번째 인덱스를 말한다. 이 테이블에서는 id가 된다.

row[1]은 할 일, {status}는  row[2]의 값이 True라면 "완료"를, False라면 "미완료"를 변수 status에 할당하여 출력한다.

 

view_todos()

할 일 조회는 매개변수가 없어서 함수 호출만 하면 된다.

 

미완료를 완료로 변경 및 등록했던 할 일 삭제는 입력한 번호와 같은 id를 찾아서 수정 및 삭제하는 형식이다.

def mark_as_done(task_id):
    try:
        with connection.cursor() as cursor:
            sql = "UPDATE tasks SET done = TRUE WHERE id = %s;"
            cursor.execute(sql, (task_id,))
            connection.commit()
    except pymysql.Error as e:
        print(f"Error: {e}")
        connection.rollback()

수정

 

def delete_todo(task_id):
    try:
        with connection.cursor() as cursor:
            sql = "DELETE FROM tasks WHERE id = %s;"
            cursor.execute(sql, (task_id,))
            connection.commit()
            print(f"할 일 {task_id}번이 삭제되었습니다.")
    except pymysql.Error as e:
        print(f"Error: {e}")
        connection.rollback()

삭제

 

호출 함수들은 이렇다.

 

# 할 일 입력
todo = input("할 일을 입력하세요 : ")
add_todo(todo)

# 할 일 조회
view_todos()

# 완료 체크하기 
task_id = input("완료한 할 일의 번호를 입력하세요: ")
mark_as_done(task_id)

# 완료 체크 후 할 일 조회
view_todos()

# 할 일 삭제하기
task_id = input("삭제할 할 일의 번호를 입력하세요: ")
delete_todo(task_id)

# 할 일 목록 조회하기 (삭제 후)
view_todos()

#연결 닫기
connection.close()

 

실행하면 이렇게 된다.

 

 

그런데 할 일 기입만 하고 수정이나 삭제할 생각이 없을 때, 또는 수정이나 삭제만 하고 싶을 때도 프로그램을 실행할 때 모든 함수가 실행되기 때문에 조금 불편하다.

그래서 콘솔에 메뉴가 뜨고, 메뉴를 선택해서 해당 함수들만 동작하도록 코드를 수정했다.

 

while True:
    print("\n===== 투두리스트 메뉴 =====")
    print("1. 할 일 추가")
    print("2. 할 일 목록 조회")
    print("3. 완료 체크")
    print("4. 할 일 삭제")
    print("5. 종료")

    choice = input("원하는 기능의 번호를 선택하세요: ")
    if choice == "1":
        todo = input("할 일을 입력하세요: ")
        add_todo(todo)

    elif choice == "2":
        view_todos()

    elif choice == "3":
        task_id = input("완료한 할 일의 번호를 입력하세요: ")
        mark_as_done(task_id)

    elif choice == "4":
        task_id = input("삭제할 할 일의 번호를 입력하세요: ")
        delete_todo(task_id)

    elif choice == "5":
        print("프로그램을 종료합니다.")
        connection.close()
        break

    else:
        print("올바른 번호를 선택하세요.")

 

메뉴의 번호를 입력해서 원하는 기능만 선택해서 할 수 있게 했다.

끝! 

 

다음엔 웹 사이트에서 실제로 체크할 수 있게 만들어봐야겠다. : )