[Python 100일 챌린지] Day 80 - Phase 8 실전 프로젝트: 할 일 관리 앱
드디어 Phase 8의 대미를 장식할 프로젝트예요! 🎉🚀
지난 10일 동안 배운 SQLite, SQL 쿼리, 트랜잭션, 데이터베이스 설계, 그리고 ORM까지… 모든 데이터베이스 개념을 한데 모아서 실전 할 일 관리 앱(Todo App)을 만들어봐요! CLI 기반으로 간단하지만, 완전한 CRUD 기능과 우선순위 관리, 완료 상태 추적 등 실무에서 사용하는 모든 기능을 구현할 거예요! 🔥
이 프로젝트를 완성하면 여러분은 데이터베이스를 자유자재로 다루는 개발자가 되는 거예요!
(45분 완독 ⭐⭐⭐⭐⭐)
🎯 프로젝트 목표
Phase 8에서 배운 모든 데이터베이스 개념을 활용하여 CLI 기반 할 일 관리 시스템을 구축해요!
🎨 사용할 데이터베이스 개념
- ✅ SQLite (Day 71-72): 데이터베이스 기초
- ✅ SQL CRUD (Day 73-74): 데이터 조작
- ✅ 고급 SQL (Day 75-76): JOIN, 서브쿼리, 집계
- ✅ 트랜잭션 & 성능 (Day 77): 데이터 무결성
- ✅ Python 연동 (Day 78): sqlite3 모듈
- ✅ ORM 개념 (Day 79): 객체 지향 데이터베이스
💡 왜 할 일 관리 앱을 만들까요? Todo 앱은 CRUD의 완벽한 예제예요! 생성(할 일 추가), 조회(목록 보기), 수정(완료 처리), 삭제(할 일 제거)를 모두 사용하죠. 게다가 우선순위, 카테고리, 날짜 관리 등 실무 개념도 녹여낼 수 있어요!
📋 프로젝트: CLI 할 일 관리 앱
프로젝트 개요
터미널에서 실행되는 강력한 할 일 관리 시스템을 만들어요! 📝
주요 기능:
- ➕ 할 일 추가: 제목, 설명, 우선순위, 카테고리
- 📋 할 일 목록: 전체/진행중/완료 필터링
- ✏️ 할 일 수정: 내용, 우선순위 변경
- ✅ 완료 처리: 진행중 ↔ 완료 토글
- 🗑️ 할 일 삭제: 선택 삭제 및 완료 항목 일괄 삭제
- 📊 통계 보기: 전체/완료/진행중 개수, 우선순위별 분포
이렇게 활용할 수 있어요! 💼
- 개인 업무 관리
- 프로젝트 태스크 추적
- 학습 계획 관리
- 쇼핑 리스트, 메모장 등
💻 단계별 구현
💡 천천히 따라 해봐요! 각 단계마다 Phase 8에서 배운 개념이 어떻게 활용되는지 주석으로 설명했어요!
1단계: 데이터베이스 설계 🏗️
먼저 테이블 구조를 설계해봐요!
erDiagram
TODOS {
int id PK
string title
string description
string category
string priority
boolean is_completed
datetime created_at
datetime completed_at
}
CATEGORIES {
int id PK
string name
int task_count
}
TODOS ||--o{ CATEGORIES : belongs_to
테이블 설계 원칙 (Day 76 활용):
- ✅ 정규화: 카테고리는 별도 테이블로 (중복 제거)
- ✅ 인덱스: 자주 검색하는 컬럼에 인덱스 추가
- ✅ 제약조건: NOT NULL, DEFAULT, UNIQUE 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"""
todo_app.py - 할 일 관리 앱
Phase 8에서 배운 모든 개념 활용!
"""
import sqlite3
from datetime import datetime
from typing import List, Optional, Tuple
from enum import Enum
# ===== 열거형 정의 =====
class Priority(Enum):
"""우선순위"""
LOW = "낮음"
MEDIUM = "보통"
HIGH = "높음"
URGENT = "긴급"
class Category(Enum):
"""카테고리"""
WORK = "업무"
PERSONAL = "개인"
STUDY = "학습"
SHOPPING = "쇼핑"
OTHER = "기타"
2단계: 데이터베이스 연결 및 초기화 🔌
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class TodoDatabase:
"""할 일 데이터베이스 관리 클래스"""
def __init__(self, db_name: str = 'todos.db'):
"""데이터베이스 초기화"""
self.db_name = db_name
self.conn = None
self.cursor = None
def connect(self):
"""데이터베이스 연결"""
self.conn = sqlite3.connect(self.db_name)
self.conn.row_factory = sqlite3.Row # 딕셔너리처럼 접근 가능
self.cursor = self.conn.cursor()
print(f"✅ 데이터베이스 연결: {self.db_name}")
def create_tables(self):
"""테이블 생성 (Day 73 활용)"""
# todos 테이블
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
category TEXT DEFAULT '기타',
priority TEXT DEFAULT '보통',
is_completed BOOLEAN DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP
)
''')
# 인덱스 생성 (검색 속도 향상)
self.cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_category
ON todos(category)
''')
self.cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_priority
ON todos(priority)
''')
self.cursor.execute('''
CREATE INDEX IF NOT EXISTS idx_completed
ON todos(is_completed)
''')
self.conn.commit()
print("✅ 테이블 생성 완료")
def close(self):
"""연결 종료"""
if self.conn:
self.conn.close()
print("✅ 데이터베이스 연결 종료")
3단계: CRUD 기능 구현 ✨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# ===== CREATE =====
def add_todo(
self,
title: str,
description: str = "",
category: str = "기타",
priority: str = "보통"
) -> int:
"""할 일 추가 (Day 73 활용)"""
try:
self.cursor.execute('''
INSERT INTO todos (title, description, category, priority)
VALUES (?, ?, ?, ?)
''', (title, description, category, priority))
self.conn.commit()
todo_id = self.cursor.lastrowid
print(f"✅ 할 일 추가 완료! (ID: {todo_id})")
return todo_id
except sqlite3.Error as e:
print(f"❌ 추가 실패: {e}")
self.conn.rollback() # Day 77 - 트랜잭션 롤백
return -1
# ===== READ =====
def get_all_todos(self, filter_completed: Optional[bool] = None) -> List[sqlite3.Row]:
"""할 일 목록 조회 (Day 74 활용)"""
if filter_completed is None:
# 전체 조회
self.cursor.execute('''
SELECT * FROM todos
ORDER BY
CASE priority
WHEN '긴급' THEN 1
WHEN '높음' THEN 2
WHEN '보통' THEN 3
WHEN '낮음' THEN 4
END,
created_at DESC
''')
else:
# 완료 여부로 필터링
self.cursor.execute('''
SELECT * FROM todos
WHERE is_completed = ?
ORDER BY
CASE priority
WHEN '긴급' THEN 1
WHEN '높음' THEN 2
WHEN '보통' THEN 3
WHEN '낮음' THEN 4
END,
created_at DESC
''', (filter_completed,))
return self.cursor.fetchall()
def get_todo_by_id(self, todo_id: int) -> Optional[sqlite3.Row]:
"""ID로 할 일 조회"""
self.cursor.execute('SELECT * FROM todos WHERE id = ?', (todo_id,))
return self.cursor.fetchone()
def search_todos(self, keyword: str) -> List[sqlite3.Row]:
"""키워드로 검색 (Day 74 - LIKE 활용)"""
self.cursor.execute('''
SELECT * FROM todos
WHERE title LIKE ? OR description LIKE ?
ORDER BY created_at DESC
''', (f'%{keyword}%', f'%{keyword}%'))
return self.cursor.fetchall()
# ===== UPDATE =====
def update_todo(
self,
todo_id: int,
title: Optional[str] = None,
description: Optional[str] = None,
category: Optional[str] = None,
priority: Optional[str] = None
) -> bool:
"""할 일 수정 (Day 74 활용)"""
# 현재 데이터 가져오기
todo = self.get_todo_by_id(todo_id)
if not todo:
print(f"❌ ID {todo_id}를 찾을 수 없습니다.")
return False
# 변경사항만 업데이트
update_fields = []
params = []
if title:
update_fields.append("title = ?")
params.append(title)
if description is not None:
update_fields.append("description = ?")
params.append(description)
if category:
update_fields.append("category = ?")
params.append(category)
if priority:
update_fields.append("priority = ?")
params.append(priority)
if not update_fields:
print("❌ 변경할 내용이 없습니다.")
return False
params.append(todo_id)
query = f"UPDATE todos SET {', '.join(update_fields)} WHERE id = ?"
try:
self.cursor.execute(query, params)
self.conn.commit()
print(f"✅ ID {todo_id} 수정 완료!")
return True
except sqlite3.Error as e:
print(f"❌ 수정 실패: {e}")
self.conn.rollback()
return False
def toggle_complete(self, todo_id: int) -> bool:
"""완료 상태 토글 (Day 74 활용)"""
todo = self.get_todo_by_id(todo_id)
if not todo:
print(f"❌ ID {todo_id}를 찾을 수 없습니다.")
return False
new_status = not todo['is_completed']
completed_at = datetime.now() if new_status else None
try:
self.cursor.execute('''
UPDATE todos
SET is_completed = ?, completed_at = ?
WHERE id = ?
''', (new_status, completed_at, todo_id))
self.conn.commit()
status = "완료" if new_status else "진행중"
print(f"✅ ID {todo_id} 상태 변경: {status}")
return True
except sqlite3.Error as e:
print(f"❌ 상태 변경 실패: {e}")
self.conn.rollback()
return False
# ===== DELETE =====
def delete_todo(self, todo_id: int) -> bool:
"""할 일 삭제 (Day 74 활용)"""
try:
self.cursor.execute('DELETE FROM todos WHERE id = ?', (todo_id,))
self.conn.commit()
if self.cursor.rowcount > 0:
print(f"✅ ID {todo_id} 삭제 완료!")
return True
else:
print(f"❌ ID {todo_id}를 찾을 수 없습니다.")
return False
except sqlite3.Error as e:
print(f"❌ 삭제 실패: {e}")
self.conn.rollback()
return False
def delete_completed_todos(self) -> int:
"""완료된 할 일 일괄 삭제"""
try:
self.cursor.execute('DELETE FROM todos WHERE is_completed = 1')
self.conn.commit()
count = self.cursor.rowcount
print(f"✅ 완료된 할 일 {count}개 삭제 완료!")
return count
except sqlite3.Error as e:
print(f"❌ 삭제 실패: {e}")
self.conn.rollback()
return 0
4단계: 통계 및 고급 기능 📊
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# ===== 통계 (Day 75-76 - 집계 함수, GROUP BY 활용) =====
def get_statistics(self) -> dict:
"""통계 정보 조회"""
stats = {}
# 전체/완료/진행중 개수
self.cursor.execute('''
SELECT
COUNT(*) as total,
SUM(CASE WHEN is_completed = 1 THEN 1 ELSE 0 END) as completed,
SUM(CASE WHEN is_completed = 0 THEN 1 ELSE 0 END) as in_progress
FROM todos
''')
row = self.cursor.fetchone()
stats['total'] = row['total']
stats['completed'] = row['completed']
stats['in_progress'] = row['in_progress']
# 우선순위별 분포
self.cursor.execute('''
SELECT priority, COUNT(*) as count
FROM todos
WHERE is_completed = 0
GROUP BY priority
ORDER BY
CASE priority
WHEN '긴급' THEN 1
WHEN '높음' THEN 2
WHEN '보통' THEN 3
WHEN '낮음' THEN 4
END
''')
stats['by_priority'] = dict(self.cursor.fetchall())
# 카테고리별 분포
self.cursor.execute('''
SELECT category, COUNT(*) as count
FROM todos
WHERE is_completed = 0
GROUP BY category
ORDER BY count DESC
''')
stats['by_category'] = dict(self.cursor.fetchall())
return stats
def get_overdue_tasks(self) -> List[sqlite3.Row]:
"""오래된 미완료 할 일 (7일 이상)"""
self.cursor.execute('''
SELECT *
FROM todos
WHERE is_completed = 0
AND datetime(created_at) <= datetime('now', '-7 days')
ORDER BY created_at ASC
''')
return self.cursor.fetchall()
5단계: CLI 인터페이스 🖥️
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
class TodoApp:
"""할 일 관리 앱 CLI"""
def __init__(self):
self.db = TodoDatabase()
self.db.connect()
self.db.create_tables()
def display_menu(self):
"""메인 메뉴 출력"""
print("\n" + "="*50)
print("📝 할 일 관리 앱")
print("="*50)
print("1. ➕ 할 일 추가")
print("2. 📋 할 일 목록 보기")
print("3. ✏️ 할 일 수정")
print("4. ✅ 완료 처리")
print("5. 🗑️ 할 일 삭제")
print("6. 🔍 검색")
print("7. 📊 통계 보기")
print("8. 🧹 완료 항목 정리")
print("0. 🚪 종료")
print("="*50)
def display_todos(self, todos: List[sqlite3.Row]):
"""할 일 목록 출력"""
if not todos:
print("\n📭 할 일이 없습니다!")
return
print(f"\n{'ID':<5} {'상태':<8} {'우선순위':<8} {'카테고리':<10} {'제목':<30} {'생성일':<20}")
print("-" * 100)
for todo in todos:
status = "✅ 완료" if todo['is_completed'] else "⏳ 진행중"
priority_icon = {
'긴급': '🔴',
'높음': '🟠',
'보통': '🟡',
'낮음': '🟢'
}.get(todo['priority'], '⚪')
created = datetime.fromisoformat(todo['created_at']).strftime('%Y-%m-%d %H:%M')
print(
f"{todo['id']:<5} "
f"{status:<8} "
f"{priority_icon} {todo['priority']:<6} "
f"{todo['category']:<10} "
f"{todo['title']:<30} "
f"{created:<20}"
)
def add_todo_interactive(self):
"""할 일 추가 (대화형)"""
print("\n➕ 새 할 일 추가")
title = input("제목: ").strip()
if not title:
print("❌ 제목은 필수입니다!")
return
description = input("설명 (선택): ").strip()
print("\n카테고리 선택:")
for i, cat in enumerate(Category, 1):
print(f" {i}. {cat.value}")
cat_choice = input("선택 (기본: 기타): ").strip()
category = list(Category)[int(cat_choice)-1].value if cat_choice.isdigit() else "기타"
print("\n우선순위 선택:")
for i, pri in enumerate(Priority, 1):
print(f" {i}. {pri.value}")
pri_choice = input("선택 (기본: 보통): ").strip()
priority = list(Priority)[int(pri_choice)-1].value if pri_choice.isdigit() else "보통"
self.db.add_todo(title, description, category, priority)
def view_todos_interactive(self):
"""할 일 목록 보기 (대화형)"""
print("\n📋 목록 보기")
print("1. 전체")
print("2. 진행중만")
print("3. 완료만")
choice = input("선택: ").strip()
if choice == "2":
todos = self.db.get_all_todos(filter_completed=False)
elif choice == "3":
todos = self.db.get_all_todos(filter_completed=True)
else:
todos = self.db.get_all_todos()
self.display_todos(todos)
def update_todo_interactive(self):
"""할 일 수정 (대화형)"""
todo_id = input("\n✏️ 수정할 할 일 ID: ").strip()
if not todo_id.isdigit():
print("❌ 올바른 ID를 입력하세요!")
return
todo_id = int(todo_id)
todo = self.db.get_todo_by_id(todo_id)
if not todo:
print(f"❌ ID {todo_id}를 찾을 수 없습니다!")
return
print(f"\n현재 제목: {todo['title']}")
title = input("새 제목 (Enter=유지): ").strip() or None
print(f"현재 설명: {todo['description']}")
description = input("새 설명 (Enter=유지): ").strip()
description = description if description else None
self.db.update_todo(todo_id, title=title, description=description)
def toggle_complete_interactive(self):
"""완료 처리 (대화형)"""
todo_id = input("\n✅ 완료 처리할 할 일 ID: ").strip()
if not todo_id.isdigit():
print("❌ 올바른 ID를 입력하세요!")
return
self.db.toggle_complete(int(todo_id))
def delete_todo_interactive(self):
"""할 일 삭제 (대화형)"""
todo_id = input("\n🗑️ 삭제할 할 일 ID: ").strip()
if not todo_id.isdigit():
print("❌ 올바른 ID를 입력하세요!")
return
confirm = input(f"정말 삭제하시겠습니까? (y/N): ").strip().lower()
if confirm == 'y':
self.db.delete_todo(int(todo_id))
def search_todos_interactive(self):
"""검색 (대화형)"""
keyword = input("\n🔍 검색어: ").strip()
if not keyword:
print("❌ 검색어를 입력하세요!")
return
todos = self.db.search_todos(keyword)
print(f"\n검색 결과: '{keyword}'")
self.display_todos(todos)
def show_statistics(self):
"""통계 출력"""
stats = self.db.get_statistics()
print("\n" + "="*50)
print("📊 통계")
print("="*50)
print(f"\n📌 전체 할 일: {stats['total']}개")
print(f" ✅ 완료: {stats['completed']}개")
print(f" ⏳ 진행중: {stats['in_progress']}개")
if stats['total'] > 0:
completion_rate = (stats['completed'] / stats['total']) * 100
print(f" 📈 완료율: {completion_rate:.1f}%")
print("\n🎯 우선순위별 진행중 할 일:")
for priority, count in stats['by_priority'].items():
icon = {'긴급': '🔴', '높음': '🟠', '보통': '🟡', '낮음': '🟢'}.get(priority, '⚪')
print(f" {icon} {priority}: {count}개")
print("\n📁 카테고리별 진행중 할 일:")
for category, count in stats['by_category'].items():
print(f" {category}: {count}개")
# 오래된 할 일
overdue = self.db.get_overdue_tasks()
if overdue:
print(f"\n⚠️ 7일 이상 된 미완료 할 일: {len(overdue)}개")
for todo in overdue[:3]:
print(f" • {todo['title']}")
def cleanup_completed(self):
"""완료 항목 정리"""
confirm = input("\n🧹 완료된 모든 할 일을 삭제하시겠습니까? (y/N): ").strip().lower()
if confirm == 'y':
self.db.delete_completed_todos()
def run(self):
"""앱 실행"""
print("🚀 할 일 관리 앱을 시작합니다!")
while True:
self.display_menu()
choice = input("\n선택: ").strip()
if choice == '1':
self.add_todo_interactive()
elif choice == '2':
self.view_todos_interactive()
elif choice == '3':
self.update_todo_interactive()
elif choice == '4':
self.toggle_complete_interactive()
elif choice == '5':
self.delete_todo_interactive()
elif choice == '6':
self.search_todos_interactive()
elif choice == '7':
self.show_statistics()
elif choice == '8':
self.cleanup_completed()
elif choice == '0':
print("\n👋 할 일 관리 앱을 종료합니다!")
self.db.close()
break
else:
print("❌ 올바른 메뉴를 선택하세요!")
# ===== 메인 프로그램 =====
def main():
"""메인 함수"""
app = TodoApp()
app.run()
if __name__ == "__main__":
main()
🎯 실행 결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
🚀 할 일 관리 앱을 시작합니다!
✅ 데이터베이스 연결: todos.db
✅ 테이블 생성 완료
==================================================
📝 할 일 관리 앱
==================================================
1. ➕ 할 일 추가
2. 📋 할 일 목록 보기
3. ✏️ 할 일 수정
4. ✅ 완료 처리
5. 🗑️ 할 일 삭제
6. 🔍 검색
7. 📊 통계 보기
8. 🧹 완료 항목 정리
0. 🚪 종료
==================================================
선택: 1
➕ 새 할 일 추가
제목: Python 100일 챌린지 완주하기
설명 (선택): 매일 꾸준히 학습하기
카테고리 선택:
1. 업무
2. 개인
3. 학습
4. 쇼핑
5. 기타
선택 (기본: 기타): 3
우선순위 선택:
1. 낮음
2. 보통
3. 높음
4. 긴급
선택 (기본: 보통): 3
✅ 할 일 추가 완료! (ID: 1)
==================================================
선택: 2
📋 목록 보기
1. 전체
2. 진행중만
3. 완료만
선택: 2
ID 상태 우선순위 카테고리 제목 생성일
----------------------------------------------------------------------------------------------------
1 ⏳ 진행중 🟠 높음 학습 Python 100일 챌린지 완주하기 2025-05-19 09:00
2 ⏳ 진행중 🔴 긴급 업무 프로젝트 마감 2025-05-19 09:05
3 ⏳ 진행중 🟡 보통 개인 운동하기 2025-05-19 09:10
==================================================
선택: 7
==================================================
📊 통계
==================================================
📌 전체 할 일: 5개
✅ 완료: 2개
⏳ 진행중: 3개
📈 완료율: 40.0%
🎯 우선순위별 진행중 할 일:
🔴 긴급: 1개
🟠 높음: 1개
🟡 보통: 1개
📁 카테고리별 진행중 할 일:
학습: 1개
업무: 1개
개인: 1개
🎊 실행 결과 해석
이 프로젝트가 얼마나 실용적인지 볼까요?
데이터베이스 설계:
- ✅ 정규화된 테이블 구조
- ✅ 적절한 인덱스로 검색 속도 향상
- ✅ 제약조건으로 데이터 무결성 보장
기능 구현:
- ✅ 완전한 CRUD 구현
- ✅ 고급 SQL (집계, GROUP BY, CASE) 활용
- ✅ 트랜잭션으로 안전한 데이터 처리
- ✅ 직관적인 CLI 인터페이스
실무 적용:
- ✅ 에러 처리 및 롤백
- ✅ 사용자 친화적 UX
- ✅ 확장 가능한 구조
💡 프로젝트에서 활용한 Phase 8 개념 총정리
1. SQLite 기초 (Day 71-72) 🗄️
1
2
conn = sqlite3.connect('todos.db')
cursor = conn.cursor()
어디에 썼나요? 데이터베이스 연결 및 커서 생성!
2. SQL CRUD (Day 73-74) 📝
1
2
3
4
5
6
7
8
9
10
11
# CREATE
INSERT INTO todos VALUES (?, ?, ?)
# READ
SELECT * FROM todos WHERE is_completed = 0
# UPDATE
UPDATE todos SET title = ? WHERE id = ?
# DELETE
DELETE FROM todos WHERE id = ?
어디에 썼나요? 모든 데이터 조작!
3. 고급 SQL (Day 75-76) 🎯
1
2
3
4
5
6
7
8
9
10
11
# 집계 함수
COUNT(*), SUM(), AVG()
# GROUP BY
GROUP BY category
# CASE 문
CASE priority WHEN '긴급' THEN 1 END
# 정렬
ORDER BY priority, created_at DESC
어디에 썼나요? 통계 계산 및 우선순위 정렬!
4. 트랜잭션 (Day 77) 🔒
1
2
3
4
5
try:
cursor.execute(...)
conn.commit()
except:
conn.rollback()
어디에 썼나요? 안전한 데이터 수정!
5. Python 연동 (Day 78) 🐍
1
2
conn.row_factory = sqlite3.Row # 딕셔너리처럼 접근
cursor.fetchall(), fetchone()
어디에 썼나요? 파이썬과 데이터베이스 통합!
6. ORM 개념 (Day 79) 🏗️
1
2
3
4
# 클래스 기반 설계
class TodoDatabase:
def add_todo(self, ...):
pass
어디에 썼나요? 객체 지향 데이터베이스 관리!
🚀 확장 아이디어
프로젝트를 더 발전시켜봐요!
- 🌐 웹 인터페이스
- Flask/FastAPI로 REST API 구현
- React/Vue로 프론트엔드 개발
- 📱 모바일 연동
- RESTful API 제공
- 크로스 플랫폼 동기화
- 🔔 알림 시스템
- 마감일 설정 및 리마인더
- 이메일/SMS 알림
- 👥 멀티 유저
- 사용자 인증/권한 관리
- 팀 협업 기능
- 📊 시각화
- matplotlib로 통계 그래프
- 완료율 트렌드 분석
- ☁️ 클라우드 동기화
- PostgreSQL/MySQL 연동
- 클라우드 백업
📝 Phase 8 핵심 요약
배운 데이터베이스 개념들 🎓
- SQLite 기초 (Day 71-72): 데이터베이스 개념, 테이블, SQL 기초
- SQL CRUD (Day 73-74): INSERT, SELECT, UPDATE, DELETE
- 고급 SQL (Day 75-76): JOIN, 서브쿼리, 집계 함수, GROUP BY
- 트랜잭션 & 성능 (Day 77): ACID, 인덱스, 쿼리 최적화
- Python 연동 (Day 78): sqlite3 모듈, 파라미터 바인딩
- ORM 개념 (Day 79): SQLAlchemy, 객체-관계 매핑
실무에서 이렇게 써요! 💼
- 웹 개발: Django/Flask ORM으로 데이터베이스 관리
- 데이터 분석: SQL로 복잡한 통계 쿼리
- 앱 개발: 로컬 데이터 저장 (설정, 캐시 등)
- 자동화: 데이터 수집 및 저장 스크립트
- 비즈니스 로직: 트랜잭션으로 안전한 데이터 처리
🎯 도전 과제
스스로 기능을 추가해봐요! 💪
- 마감일 기능 추가
- Hint: due_date 컬럼 추가, datetime 비교
- 서브태스크 기능
- Hint: parent_id로 계층 구조 구현
- 태그 시스템
- Hint: tags 테이블 별도 생성, Many-to-Many
- 백업/복원 기능
- Hint: SQL DUMP, CSV 내보내기
🔗 관련 자료
📚 이전 학습
Day 79: Python DB 고급 - ORM 개념 ⭐⭐⭐⭐⭐
어제는 ORM으로 데이터베이스를 객체처럼 다루는 방법을 배웠어요!
📚 다음 학습
Phase 9: 웹 개발 with Flask 🌐
다음 Phase에서는 Flask로 웹 애플리케이션을 만드는 방법을 배워요! 데이터베이스 지식을 활용해 완전한 웹 서비스를 구축해봐요!
🎉 축하합니다! Phase 8 완료!
여러분은 이제 데이터베이스 마스터예요! 🏆
10일 동안 배운 내용:
- ✅ SQLite로 데이터베이스 기초 완벽 이해
- ✅ SQL CRUD로 데이터 자유자재로 조작
- ✅ 고급 SQL로 복잡한 쿼리 작성
- ✅ 트랜잭션으로 안전한 데이터 관리
- ✅ Python으로 데이터베이스 완벽 통합
- ✅ ORM 개념으로 객체 지향 데이터베이스
- ✅ 실전 Todo 앱으로 모든 개념 종합!
이제 어떤 데이터든 저장하고 관리할 수 있어요! 데이터베이스는 모든 애플리케이션의 핵심이랍니다! 💪
다음 Phase에서는 이 데이터베이스 지식을 활용해서 웹 애플리케이션을 만들어봐요! 🚀
“데이터베이스를 마스터한 여러분, 이제 진정한 백엔드 개발자의 길로 접어들었어요!” 🎊
Day 80/100 Phase 8 완료! #100DaysOfPython
