Chap.14 파일[예제] - Database Application
파일[예제]
Database Application
>> pip install mysqlclient
현재 sqldb.tbladdr 상황
1단계(베이스)
뼈대 만들기
# DB+App.py
import sys
from myapp import Application, MenuItem
class DBApp(Application): # 상속
def __init__(self):
super().__init__()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def print_list(self):
print("목록보기...")
def add(self):
print("추가")
def update(self):
print("수정")
def remove(self):
print("삭제")
def exit(self):
sys.exit(0)
if __name__ == '__main__': # 단독 실행 여부 확인인
app = DBApp()
app.run() # 부모 Class에 정의되어 있다.
결과
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 1
추가
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 2
수정
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 3
삭제
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 0
목록보기...
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 0
목록보기...
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 4
2단계(연결)
Connection & Close 어디서 해주어야 하나.
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application): # 상속
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
# self.db가 아니라 db 로 했으면 지역변수 db를 쓰겠다는 뜻이므로 인스턴스 변수로 관리해야한다.
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def print_list(self):
print("목록보기...")
def add(self):
print("추가")
def update(self):
print("수정")
def remove(self):
print("삭제")
def exit(self): # exit 할 때 커서와 db 닫아준다.
answer = input("종료하시겠습니까?([y]/n) :") # y 또는 Y 입력 받으면 종료
if answer in ["y", "Y", ""]: # "" : Enter만 입력받아도 종료 (디폴트 설정)
self.cursor.close()
self.db.close()
sys.exit(0)
else: app.run()
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 4
종료하시겠습니까?([y]/n) Y
3단계(목록)
목록보기 - print_list() ★★★
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def print_list(self):
try:
sql = "SELECT count(*) from tblAddr" # 컬럼의 NULL 값을 신경 안쓴다.
self.cursor.execute(sql) # 결과가 있고 그 결과는 항상 한개이다.
row = self.cursor.fetchone() # 집계함수의 특성상 값이 항상 보장된다. (if 검사 필요 X)
total = row[0] # 전체 데이터 건수의 올바른 방법 (필터링할 때도 유지)
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql) # 아직은 사용안하지만 영향받은 행의 수 리턴됨
rows = self.cursor.fetchall()
print("="*50)
print("No 이름 전화번호 주소")
print("-"*50)
for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
def add(self):
print("추가")
def update(self):
print("수정")
def remove(self):
print("삭제")
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.cursor.close()
self.db.close()
sys.exit(0)
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택] 0
==================================================
No 이름 전화번호 주소
--------------------------------------------------
1 : 김상형 123-4567 오산
2 : 한경은 555-1004 수원
3 : 한주완 444-1092 대전
4 : 홍길동 1111-1111 군포
==================================================
(총 4 건)
[메뉴] 0:목록 1:추가 2:수정 3:삭제 4:종료
선택]
4단계(추가)
추가 - add()
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.cursor.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
sql = "SELECT count(*) from tblAddr"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("="*50)
print("No 이름 전화번호 주소")
print("-"*50)
for ix, row in enumerate(rows, 1):
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ")
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit() # 실제 데이터베이스 반영
# insert, update, delete 때는 필요하다!
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
print("삭제")
def update(self):
print("수정")
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택] 2
이름 : 고길동
전화번호: 123-1234
주소 : 서울
추가 완료
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택]
5단계(삭제)
삭제 - remove()
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.cursor.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
sql = "SELECT count(*) from tblAddr"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("="*50)
print("No 이름 전화번호 주소")
print("-"*50)
for ix, row in enumerate(rows, 1):
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ")
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit()
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
self.db.commit() # ☆
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
print("수정")
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택] 4
이름: 고길동
삭제 완료
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택]
6단계(수정)
수정 - update()
1. 이름 입력 받아서 데이터 있는지 확인하기
2. 기존의 데이터 보여주고, 그냥 넘어가면 수정하지 않게
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.cursor.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
sql = "SELECT count(*) from tblAddr"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("="*50)
print("No 이름 전화번호 주소")
print("-"*50)
for ix, row in enumerate(rows, 1):
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ")
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit() # 실제 데이터베이스 반영
# insert, update, delete 때는 필요하다!
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
self.db.commit()
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
try:
name = input("이름: ")
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
data = self.cursor.fetchone()
if not data: # 데이터가 없다면
print(f"{name} 데이터가 없습니다.")
return # 리턴
phone = input(f"전화번호({data[1]}): ")
if not phone: # 비어있는 문자열 받았을 때
phone = data[1]
addr = input(f"주소({data[2]}): ")
if not addr: # 비어있는 문자열 받았을 때
addr = data[2]
sql = """
UPDATE tblAddr SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (phone, addr, name)) # 순서 신경쓰자
self.db.commit()
print("수정 완료")
except Exception as e:
print(e)
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택] 3
이름: 홍길동
전화번호(1111-1111): 123-1234
주소(군포):
수정 완료
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택] 0
==================================================
No 이름 전화번호 주소
--------------------------------------------------
1 : 김상형 123-4567 오산
2 : 한경은 555-1004 수원
3 : 한주완 444-1092 대전
4 : 홍길동 123-1234 군포
==================================================
(총 4 건)
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택]
7단계(검색) - 메뉴 추가
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.cursor = self.db.cursor()
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search)) # 검색 메뉴 추가
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.cursor.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
sql = "SELECT count(*) from tblAddr"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("=" * 50)
print("No 이름 전화번호 주소")
print("-" * 50)
for ix, row in enumerate(rows, 1):
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ")
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit()
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
self.db.commit()
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
try:
name = input("이름: ")
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
data = self.cursor.fetchone()
if not data:
print(f"{name} 데이터가 없습니다.")
return
phone = input(f"전화번호({data[1]}): ")
if not phone:
phone = data[1]
addr = input(f"주소({data[2]}): ")
if not addr:
addr = data[2]
sql = """
UPDATE tblAddr SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (phone, addr, name))
self.db.commit()
print("수정 완료")
except Exception as e:
print(e)
def search(self):
try:
name = input("이름 : ")
sql = f"SELECT count(*) from tblAddr WHERE name LIKE '%{name}%'"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = f"SELECT * from tblAddr WHERE name LIKE '%{name}%'"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
print("=" * 50)
print(f"(총 {total} 건)")
except Exception as e:
print(e)
if __name__ == '__main__':
app = DBApp()
app.run()
결과
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택] 1
이름 : 한
==================================================
No 이름 전화번호 주소
--------------------------------------------------
1 : 한경은 555-1004 수원
2 : 한주완 444-1092 대전
==================================================
(총 2 건)
[메뉴] 0:목록 1:검색 2:추가 3:수정 4:삭제 5:종료
선택]
method 화(1)
# addr_ui.py
def print_list(total, rows):
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
print("=" * 50)
print(f"(총 {total} 건)")
# addr_repository.py
class AddressRepositrory:
def __init__(self, db): # App은 db객체만 다루게 하기 위해
self.cursor = db.cursor() # SQL 실행을 위함
def close(self):
self.cursor.close()
def get_total(self): # 데이터 건수 함수
sql = "SELECT count(*) FROM tblAddr"
self.cursor.execute(sql)
row = self.cursor.fetchone()
return row[0]
def get_list(self):
sql = "SELECT * FROM tblAddr"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
return rows
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
from addr_repository import AddressRepositrory # 새로 만든 모듈 import
from addr_ui import * # 새로 만든 모듈 import
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
# self.cursor = self.db.cursor() # 이제 필요없다.
self.repo = AddressRepositrory(self.db)
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search)) # 검색 메뉴 추가
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
# self.cursor.close()
self.repo.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
# sql = "SELECT count(*) from tblAddr" # 컬럼의 NULL 값을 신경 안쓴다.
# self.cursor.execute(sql) # 결과가 있고 그 결과는 항상 한개이다.
# row = self.cursor.fetchone() # 집계함수의 특성상 값이 항상 보장된다. (if 검사 필요 X)
# total = row[0] # 전체 데이터 건수의 올바른 방법 (필터링할 때도 유지)
total = self.repo.get_total() # 이렇게 한줄로 처리가능
# sql = "SELECT * FROM tblAddr"
# self.cursor.execute(sql) # 아직은 사용안하지만 영향받은 행의 수 리턴됨
# rows = self.cursor.fetchall()
rows = self.repo.get_list()
# print("="*50)
# print("No 이름 전화번호 주소")
# print("-"*50)
# for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
# print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
# print("=" * 50)
# print(f"(총 {total} 건)")
print_list(total, rows)
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit() # 실제 데이터베이스 반영
# insert, update, delete 때는 필요하다!
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
self.db.commit() # ☆
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
try:
name = input("이름: ")
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
data = self.cursor.fetchone()
if not data: # 데이터가 없다면
print(f"{name} 데이터가 없습니다.")
return # 리턴
phone = input(f"전화번호({data[1]}): ")
if not phone: # 비어있는 문자열 받았을 때
phone = data[1]
addr = input(f"주소({data[2]}): ")
if not addr: # 비어있는 문자열 받았을 때
addr = data[2]
sql = """
UPDATE tblAddr SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (phone, addr, name)) # 순서 신경쓰자
self.db.commit()
print("수정 완료")
except Exception as e:
print(e)
def search(self):
try:
name = input("이름 : ")
sql = f"SELECT count(*) from tblAddr WHERE name LIKE '%{name}%'"
self.cursor.execute(sql)
row = self.cursor.fetchone()
total = row[0]
sql = f"SELECT * from tblAddr WHERE name LIKE '%{name}%'"
self.cursor.execute(sql)
rows = self.cursor.fetchall()
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
except Exception as e:
print(e)
if __name__ == '__main__':
app = DBApp()
app.run()
method 화(2)
# addr_ui.py
def print_list(total, rows):
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
print("=" * 50)
print(f"(총 {total} 건)")
# addr_repository.py
class AddressRepositrory:
def __init__(self, db): # App은 db객체만 다루게 하기 위해
self.cursor = db.cursor() # SQL 실행을 위함
def close(self):
self.cursor.close()
def get_total(self, where=''): # 디폴드는 where절 없는거
sql = "SELECT count(*) FROM tblAddr " + where # 주의! 스페이스
self.cursor.execute(sql)
row = self.cursor.fetchone()
return row[0]
def get_list(self, where=''):
sql = "SELECT * FROM tblAddr " + where
self.cursor.execute(sql)
rows = self.cursor.fetchall()
return rows
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
from addr_repository import AddressRepositrory # 새로 만든 모듈 import
from addr_ui import * # 새로 만든 모듈 import
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
# self.cursor = self.db.cursor() # 이제 필요없다.
self.repo = AddressRepositrory(self.db)
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search)) # 검색 메뉴 추가
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
# self.cursor.close()
self.repo.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
# sql = "SELECT count(*) from tblAddr" # 컬럼의 NULL 값을 신경 안쓴다.
# self.cursor.execute(sql) # 결과가 있고 그 결과는 항상 한개이다.
# row = self.cursor.fetchone() # 집계함수의 특성상 값이 항상 보장된다. (if 검사 필요 X)
# total = row[0] # 전체 데이터 건수의 올바른 방법 (필터링할 때도 유지)
total = self.repo.get_total() # 이렇게 한줄로 처리가능
# sql = "SELECT * FROM tblAddr"
# self.cursor.execute(sql) # 아직은 사용안하지만 영향받은 행의 수 리턴됨
# rows = self.cursor.fetchall()
rows = self.repo.get_list()
# print("="*50)
# print("No 이름 전화번호 주소")
# print("-"*50)
# for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
# print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
# print("=" * 50)
# print(f"(총 {total} 건)")
print_list(total, rows)
except Exception as e:
print(e)
def add(self):
try:
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (name, phone, addr))
self.db.commit() # 실제 데이터베이스 반영
# insert, update, delete 때는 필요하다!
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
self.db.commit() # ☆
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
try:
name = input("이름: ")
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
data = self.cursor.fetchone()
if not data: # 데이터가 없다면
print(f"{name} 데이터가 없습니다.")
return # 리턴
phone = input(f"전화번호({data[1]}): ")
if not phone: # 비어있는 문자열 받았을 때
phone = data[1]
addr = input(f"주소({data[2]}): ")
if not addr: # 비어있는 문자열 받았을 때
addr = data[2]
sql = """
UPDATE tblAddr SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (phone, addr, name)) # 순서 신경쓰자
self.db.commit()
print("수정 완료")
except Exception as e:
print(e)
def search(self):
try:
name = input("이름 : ")
# sql = f"SELECT count(*) from tblAddr WHERE name LIKE '%{name}%'"
# self.cursor.execute(sql)
# row = self.cursor.fetchone()
# total = row[0]
#
# sql = f"SELECT * from tblAddr WHERE name LIKE '%{name}%'"
# self.cursor.execute(sql)
# rows = self.cursor.fetchall()
#
# print("=" * 50)
# header = ("이름", "전화번호", "주소")
# print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
# print("-" * 50)
# for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
# print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
# print("=" * 50)
# print(f"(총 {total} 건)")
where = f"WHERE name LIKE '%{name}%'"
total = self.repo.get_total(where)
rows = self.repo.get_list(where)
print_list(total, rows)
except Exception as e:
print(e)
if __name__ == '__main__':
app = DBApp()
app.run()
method 화(3)
# addr_ui.py
def print_list(total, rows):
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
print("=" * 50)
print(f"(총 {total} 건)")
def input_addr_info():
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
return name, phone, addr # 튜플로 리턴된다.
def input_now_addr(data):
phone = input(f"전화번호({data[1]}): ")
if not phone:
phone = data[1]
addr = input(f"주소({data[2]}): ")
if not addr:
addr = data[2]
return data[0], phone, addr
# addr_repository.py
class AddressRepositrory:
def __init__(self, db): # App은 db객체만 다루게 하기 위해
self.cursor = db.cursor() # SQL 실행을 위함
def close(self):
self.cursor.close()
def get_total(self, where=''): # 디폴드는 where절 없는거
sql = "SELECT count(*) FROM tblAddr " + where # 주의! 스페이스
self.cursor.execute(sql)
row = self.cursor.fetchone()
return row[0]
def get_list(self, where=''):
sql = "SELECT * FROM tblAddr " + where
self.cursor.execute(sql)
rows = self.cursor.fetchall()
return rows
def insert(self, data):
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, data)
def remove(self, name):
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
def get_one(self, name):
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
return self.cursor.fetchone()
def update(self, data):
sql = """
UPDATE tblAddr
SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (data[1], data[2], data[0]))
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
from addr_repository import AddressRepositrory # 새로 만든 모듈 import
from addr_ui import * # 새로 만든 모듈 import
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
# self.cursor = self.db.cursor() # 이제 필요없다.
self.repo = AddressRepositrory(self.db)
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search)) # 검색 메뉴 추가
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
# self.cursor.close()
self.repo.close()
self.db.close()
sys.exit(0)
def print_list(self):
try:
# sql = "SELECT count(*) from tblAddr" # 컬럼의 NULL 값을 신경 안쓴다.
# self.cursor.execute(sql) # 결과가 있고 그 결과는 항상 한개이다.
# row = self.cursor.fetchone() # 집계함수의 특성상 값이 항상 보장된다. (if 검사 필요 X)
# total = row[0] # 전체 데이터 건수의 올바른 방법 (필터링할 때도 유지)
total = self.repo.get_total() # 이렇게 한줄로 처리가능
# sql = "SELECT * FROM tblAddr"
# self.cursor.execute(sql) # 아직은 사용안하지만 영향받은 행의 수 리턴됨
# rows = self.cursor.fetchall()
rows = self.repo.get_list()
# print("="*50)
# print("No 이름 전화번호 주소")
# print("-"*50)
# for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
# print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
# print("=" * 50)
# print(f"(총 {total} 건)")
print_list(total, rows)
except Exception as e:
print(e)
def add(self):
try:
# name = input("이름 : ")
# phone = input("전화번호: ")
# addr = input("주소 : ")
data = input_addr_info()
# sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
# self.cursor.execute(sql, (name, phone, addr))
# self.cursor.execute(sql, (name, phone, addr))
self.repo.insert(data)
self.db.commit() # 실제 데이터베이스 반영
# insert, update, delete 때는 필요하다!
print("추가 완료")
except Exception as e:
print(e)
def remove(self):
try:
name = input("이름: ")
# sql = "DELETE FROM tblAddr WHERE name = %s"
# self.cursor.execute(sql, (name,))
self.repo.remove(name)
self.db.commit() # ☆
print("삭제 완료")
except Exception as e:
print(e)
def update(self):
try:
name = input("이름: ")
# sql = "SELECT name FROM tblAddr WHERE name = %s"
# self.cursor.execute(sql, (name,))
# data = self.cursor.fetchone()
data = self.repo.get_one(name)
if not data: # 데이터가 없다면
print(f"{name} 데이터가 없습니다.")
return # 리턴
# phone = input(f"전화번호({data[1]}): ")
# if not phone: # 비어있는 문자열 받았을 때
# phone = data[1]
# addr = input(f"주소({data[2]}): ")
# if not addr: # 비어있는 문자열 받았을 때
# addr = data[2]
#
# sql = """
# UPDATE tblAddr SET
# phone = %s,
# addr = %s
# WHERE name = %s
# """
#
# self.cursor.execute(sql, (phone, addr, name)) # 순서 신경쓰자
data = input_new_addr(data)
self.repo.update(data)
self.db.commit()
print("수정 완료")
except Exception as e:
print(e)
def search(self):
try:
name = input("이름 : ")
# sql = f"SELECT count(*) from tblAddr WHERE name LIKE '%{name}%'"
# self.cursor.execute(sql)
# row = self.cursor.fetchone()
# total = row[0]
#
# sql = f"SELECT * from tblAddr WHERE name LIKE '%{name}%'"
# self.cursor.execute(sql)
# rows = self.cursor.fetchall()
#
# print("=" * 50)
# header = ("이름", "전화번호", "주소")
# print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
# print("-" * 50)
# for ix, row in enumerate(rows, 1): # No을 위해 enumerate 이용
# print(f"{ix} : {row[0]:10} {row[1]:10} {row[2]} ") # ★★★ : 뒤는 폭을 의미
# print("=" * 50)
# print(f"(총 {total} 건)")
where = f"WHERE name LIKE '%{name}%'"
total = self.repo.get_total(where)
rows = self.repo.get_list(where)
print_list(total, rows)
except Exception as e:
print(e)
if __name__ == '__main__':
app = DBApp()
app.run()
예외처리 - myapp.py
# myapp.py
class MenuItem:
def __init__(self, title, action=None):
self.title = title
self.action = action
def __str__(self):
return f"<MenuItem {self.title}>"
def __repr__(self):
return f"<MenuItem {self.title}>"
def run(self):
self.action()
class Application:
def __init__(self):
self.menu = Menu()
self.create_menu(self.menu)
def create_menu(self, menu):
pass
def run(self):
while True:
try: # 예외 처리 여기서!!!
self.menu.print()
sel = int(input("선택] "))
self.menu.run(sel)
except Exception as e:
print(e)
class Menu:
def __init__(self):
self.menus = []
def add(self, menu_item):
self.menus.append(menu_item)
def print(self):
print("[메뉴]", end=' ')
for i, menu in enumerate(self.menus):
print(f"{i}:{menu.title} ", end="")
print()
def run(self, select):
if select >= len(self.menus):
print("잘못된 메뉴 선택입니다")
return
self.menus[select].run()
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
from addr_repository import AddressRepositrory
from addr_ui import *
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.repo = AddressRepositrory(self.db)
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.repo.close()
self.db.close()
sys.exit(0)
def print_list(self):
total = self.repo.get_total()
rows = self.repo.get_list()
print_list(total, rows)
def add(self):
data = input_addr_info()
self.repo.insert(data)
self.db.commit()
print("추가 완료")
def remove(self):
name = input("이름: ")
self.repo.remove(name)
self.db.commit()
print("삭제 완료")
def update(self):
name = input("이름: ")
data = self.repo.get_one(name)
if not data:
print(f"{name} 데이터가 없습니다.")
return
data = input_now_addr(data)
self.repo.update(data)
self.db.commit()
print("수정 완료")
def search(self):
name = input("이름 : ")
where = f"WHERE name LIKE '%{name}%'"
total = self.repo.get_total(where)
rows = self.repo.get_list(where)
print_list(total, rows)
if __name__ == '__main__':
app = DBApp()
app.run()
최종 (가독성)
addr_models.py 만들기
# addr_models.py
class Addr:
def __init__(self, name, phone, addr):
self.name = name # 테이블의 컬럼명과 같다.
self.phone = phone # 테이블의 컬럼명과 같다.
self.addr = addr # 테이블의 컬럼명과 같다.
def __str__(self):
return f"<Addr {self.name}/{self.phone}/{self.addr}>"
def __repr__(self):
return f"<Addr {self.name}>"
# addr_ui.py
from addr_models import Addr # 임폴트
def print_list(total, rows):
print("=" * 50)
header = ("이름", "전화번호", "주소")
print(f"No {header[0]:10}{header[1]:10}{header[2]:10} ")
print("-" * 50)
for ix, row in enumerate(rows, 1):
print(f"{ix} : {row.name:10} {row.phone:10} {row.addr:10} ") # 인덱스 대신 필드 변수
print("=" * 50)
print(f"(총 {total} 건)")
def input_addr_info():
name = input("이름 : ")
phone = input("전화번호: ")
addr = input("주소 : ")
return Addr(name, phone, addr) # 튜플 대신
def input_now_addr(data):
phone = input(f"전화번호({data.phone}): ") # 튜플 대신
if not phone:
phone = data.phone # 튜플 대신
addr = input(f"주소({data.addr}): ") # 튜플 대신
if not addr:
addr = data.addr # 튜플 대신
return Addr(data.name, phone, addr) # 튜플 대신
# addr_repository.py
from addr_models import Addr
class AddressRepositrory:
def __init__(self, db): # App은 db객체만 다루게 하기 위해
self.cursor = db.cursor() # SQL 실행을 위함
def close(self):
self.cursor.close()
def get_total(self, where=''): # 디폴드는 where절 없는거
sql = "SELECT count(*) FROM tblAddr " + where # 주의! 스페이스
self.cursor.execute(sql)
row = self.cursor.fetchone()
return row[0]
def get_list(self, where=''):
sql = "SELECT * FROM tblAddr " + where
self.cursor.execute(sql)
rows = self.cursor.fetchall()
return (Addr(*row) for row in rows) # 변경
def get_one(self, name):
sql = "SELECT * FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
# return self.cursor.fetchone()
row = self.cursor.fetchone()
# addr = Addr(*row) # 펼쳐준다.
# return addr
if row: # 변경
return Addr(*row)
def insert(self, data):
sql = "INSERT INTO tblAddr VALUES(%s, %s, %s)"
self.cursor.execute(sql, (data.name, data.phone, data.addr)) # 변경
def remove(self, name):
sql = "DELETE FROM tblAddr WHERE name = %s"
self.cursor.execute(sql, (name,))
def update(self, data):
sql = """
UPDATE tblAddr
SET
phone = %s,
addr = %s
WHERE name = %s
"""
self.cursor.execute(sql, (data.phone, data.addr, data.name))
# DB+App.py
import sys
from myapp import Application, MenuItem
import MySQLdb
from addr_repository import AddressRepositrory
from addr_ui import *
class DBApp(Application):
def __init__(self):
super().__init__()
self.db = MySQLdb.connect(db="sqldb", host="localhost",
user="root", passwd="1234", charset='utf8')
self.repo = AddressRepositrory(self.db)
def create_menu(self, menu):
menu.add(MenuItem("목록", self.print_list))
menu.add(MenuItem("검색", self.search))
menu.add(MenuItem("추가", self.add))
menu.add(MenuItem("수정", self.update))
menu.add(MenuItem("삭제", self.remove))
menu.add(MenuItem("종료", self.exit))
def exit(self):
answer = input("종료하시겠습니까?([y]/n) ")
if answer in ["y", "Y", ""]:
self.repo.close()
self.db.close()
sys.exit(0)
def print_list(self):
total = self.repo.get_total()
rows = self.repo.get_list()
print_list(total, rows)
def add(self):
data = input_addr_info()
self.repo.insert(data)
self.db.commit()
print("추가 완료")
def remove(self):
name = input("이름: ")
self.repo.remove(name)
self.db.commit()
print("삭제 완료")
def update(self):
name = input("이름: ")
data = self.repo.get_one(name)
if not data:
print(f"{name} 데이터가 없습니다.")
return
data = input_now_addr(data)
self.repo.update(data)
self.db.commit()
print("수정 완료")
def search(self):
name = input("이름 : ")
where = f"WHERE name LIKE '%{name}%'"
total = self.repo.get_total(where)
rows = self.repo.get_list(where)
print_list(total, rows)
if __name__ == '__main__':
app = DBApp()
app.run()
Application에서는 수정사항이 없다.
클래스와 테이블이 매핑된다.
인스턴스 하나가 표현하는게 테이블의 행에 해당한다.
'인터페이스 개발 > Python' 카테고리의 다른 글
Python - 스레드 (0) | 2020.10.19 |
---|---|
Python - 파일[데이터베이스] - SQlite 데이터 베이스 (0) | 2020.07.29 |
Python - 파일[데이터베이스] - MySQL/MariaDB, 테이블 생성, 데이터 삽입, 테이블 조회, 수정 및 삭제 (0) | 2020.07.29 |
Python - [추가] - 데이터 시각화 Matplot (0) | 2020.07.28 |
Python - [추가] - 배열 데이터를 효과적으로 다루는 NumPy (0) | 2020.07.28 |
댓글