728x90
반응형
main 함수
def main():
# 기본적으로 다시 한번 DB 커넥션이 일어나게 헀다.
# 왜냐하면 위에서 DB 설정이 끝나면 다시 끊어주게 설정했기 때문
create_connection()
while True:
# 유저가 동작을 선택할 수 있게 시각적인 부분을 행겨주는 함수
option = start_page()
if option == 1:
pass
elif option == 2:
pass
elif option == 3:
pass
elif option == 4:
pass
elif option == 5:
pass
elif option == 6:
break
else:
print("error")
start_page()
def start_page(): # 파이썬 실행 후 가장 처음 보여주는
print("---------------------------------") # 33 개
print(" 도서 관리 시스템") # 9개
print("---------------------------------")
print(" 1. 도서 입력 ")
print(" 2. 도서 조회 ")
print(" 3. 도서 대출 ")
print(" 4. 도서 반납 ")
print(" 5. 도서 대출 정보 조회 ")
print(" 6. 시스템 종료 ")
# 유저가 예상 밖의 정보값을 주었을 때, 예외처리
while True:
try:
option = int(input("작업 번호를 입력해 주세요 : "))
if 1 <= option <= 6:
return option
else:
print("잘못된 입력입니다. 원하는 동작 번호를 다시 입력해 주세요.")
except ValueError:
print("잘못된 입력입니다. 원하는 동작 번호를 다시 입력해 주세요.")
ValueError: invalid literal for int() with base 10: 'b’
미리 int() 를 이용한 변수로 switch 로 구성해 놓아서 다른 형태의 값이 오면 계속해서 ValueError 로 인해 프로그램이 꺼지길래 구글링해서 예외처리를 해주었다.
조회기능 구현
def main():
create_connection()
while True:
option = start_page()
if option == 1:
pass
elif option == 2:
print("\\n")
print("도서 검색 기능 실행!")
print("\\n")
search_book() # 유저가 2번을 선택했을 때 실행,
elif option == 3:
pass
elif option == 4:
pass
elif option == 5:
pass
elif option == 6:
break
else:
print("error")
search_book()
사실 고민을 좀 많이 했는데, 조회를 동작하면서 계속해서 작업하거나 프로그램을 종료하는 과정들이 있을 것이라 생각해서 재귀함수를 사용하게 되었는데, 이게 스택으로 쌓이면서 루프 안에 갇혀 종료를 2번씩 해야하는, 유저입장에서 불편한 상황이 발생했다.
이를 해결하기 위해 class 로 예외처리로 해결해 보았다.
또한, 쿼리를 넣을때 유저의 입력값을 넣으려면 동적 변수를 사용해야하는데 이때 튜플형태로 작성해서 %s 로 넣어줘야한다. 해당 값이 정수형이든 문자형이든 쿼리에서는 모두 문자형으로 사용해야하니 이점 주의해서 작성해야 할 것 같다.
파이썬 에러 TOP 7 (오류 메시지 종류와 해결 방법) | 코드잇
def search_book(): # 조회 작업
# 다시 DB 에연결해두기
connection = psycopg2.connect(host=DATABASE_HOST, user=DATABASE_USER, password=DATABASE_PASSWORD,
dbname=DATABASE_NAME, port=DATABASE_PORT)
cursor = connection.cursor()
while True:
search_option = search_book_option()
# 도서 제목을 입력받아 해당 글자가 들어간 제목을 가진 도서 모두 조회
if search_option == 1:
try:
book_title = str(input("\\n검색하려는 도서 이름을 입력하세요 :"))
cursor.execute("""SELECT * FROM books WHERE title LIKE %s;""", ('%' + book_title + '%',))
except UnicodeError:
pass
rows = cursor.fetchall()
if len(rows) == 0: # 혹시 입력한 정보로 찾을 수 없을 경우 돌아가게끔 처리
print("\\n")
print("\\n")
print("\\n해당 이름을 가진 도서는 찾을 수 없습니다.")
print("다시 검색해 주세요.\\n")
continue
print("------------------------------------------------------------------")
print(" ID | title | Author | Publisher | Availability |")
print("------------------------------------------------------------------")
for row in rows: # 아직 꾸미지 않은 상태
print(row)
print("\\n")
next_action = str(input("다음 작업이 있습니까? [Y/N] :"))
if next_action.upper() == "Y":
search_book() # 재귀
elif next_action.upper() == "N":
# 다음 작업이 없이 프로그램이 종료될테니 데이터베이스와 연결 종료
print("DB close executed")
cursor.close()
connection.close()
print("DB close done")
raise ExitProgram
else:
print("\\n")
print("잘못 입력하셨습니다. 도서 검색 옵션으로 되돌아 갑니다.")
print("\\n")
# 도서 번호를 입력받아 검색
elif search_option == 2:
try:
book_id = int(input("\\n검색하려는 도서의 ID 를 입력해 주세요. :"))
cursor.execute(
"""SELECT b.*, l.loan_id, l.loan_date, l.return_date FROM books AS b
LEFT JOIN (SELECT loan_id, book_id, loan_date, return_date FROM loans WHERE return_date IS NULL) AS l ON b.book_id = l.book_id
WHERE b.book_id = %s;""", (book_id,)) # SQL 문은 정수형 이런거 상관 없이 %s 로 변수를 받는다.
except ValueError:
pass
row = cursor.fetchall()
if len(row) == 0: # 혹시 입력한 정보로 찾을 수 없을 경우 돌아가게끔 처리
print("\\n해당 ID를 가진 도서는 찾을 수 없습니다.")
print("다시 검색해 주세요.\\n")
continue
print(
"------------------------------------------------------------------------------------------------------------")
print(
"| Book ID | title | Author | Publisher | Availability | LoanID | Taken Date | Return Date |")
print(
"------------------------------------------------------------------------------------------------------------")
print(row)
print("\\n")
next_action = str(input("다음 작업이 있습니까? [Y/N] :"))
if next_action.upper() == "Y":
search_book() # 재귀
elif next_action.upper() == "N":
# 다음 작업이 없이 프로그램이 종료될테니 데이터베이스와 연결 종료
print("DB close executed")
cursor.close()
connection.close()
print("DB close done")
raise ExitProgram
else:
print("\\n")
print("잘못 입력하셨습니다. 도서 검색 옵션으로 되돌아 갑니다.")
print("\\n")
# 모든 목록 조회
elif search_option == 3:
cursor.execute("""
SELECT * FROM books;
""")
rows = cursor.fetchall()
print("\\n현재 모든 도서 정보:")
print("------------------------------------------------------------------")
print(" ID | title | Author | Publisher | Availability |")
print("------------------------------------------------------------------")
for row in rows: # 아직 꾸미지 않은 상태
print(row)
print("\\n")
next_action = str(input("다음 작업이 있습니까? [Y/N] :"))
if next_action.upper() == "Y":
search_book()
elif next_action.upper() == "N":
# 다음 작업이 없이 프로그램이 종료될테니 데이터베이스와 연결 종료
print("DB close executed")
cursor.close()
connection.close()
print("DB close done")
raise ExitProgram
elif search_option == 0:
print("\\n")
print("이전 페이지로 돌아갑니다.")
print("\\n")
# 다음 작업이 없이 메인으로 돌아가니 데이터베이스와 연결 종료
print("DB close executed")
cursor.close()
connection.close()
print("DB close done")
raise ReturnToMainMenu
additional code
# root 인덴트에 작성해서 다른 함수에서도 가져다 쓸 수 있게 하자
class ExitProgram(Exception): # 중첩된 루프 안에서 프로그램을 바로 종료하기 위함
pass
class ReturnToMainMenu(Exception): # 중첩된 루프안에서 프로그램 메인으로 돌아가기 위함
pass
변경된 main 함수
def main():
create_connection()
# try/except 문으로 중첩을 벗겨내는 작업을 수행해 보았다.
try:
while True:
option = start_page()
if option == 1:
pass
elif option == 2:
print("\\n")
print("도서 검색 기능 실행!")
print("\\n")
search_book()
elif option == 3:
pass
elif option == 4:
pass
elif option == 5:
pass
elif option == 6:
print("\\n")
print("시스템을 종료합니다.")
print("\\n")
break
else:
print("error")
except ReturnToMainMenu:
main()
except ExitProgram:
print("\\n")
print("시스템을 종료합니다.")
print("\\n")
insert 기능
- insert 기능id 값이 자동으로 생성되지 않아서 발생하는 에러해결방법으로는 INTEGER 로 선언해서 만들었던 내용을 SERIAL 로 바꾸면 된다고 한다.
library=# \\dt List of relations Schema | Name | Type | Owner --------+-------+-------+------------- public | books | table | kim public | loans | table | kim (2 rows) library=# \\d books Table "public.books" Column | Type | Collation | Nullable | Default --------------+------------------------+-----------+----------+---------------------------------------- book_id | integer | | not null | nextval('books_book_id_seq'::regclass) title | character varying(100) | | not null | author | character varying(50) | | not null | publisher | character varying(50) | | not null | is_available | boolean | | not null | true Indexes: "books_pkey" PRIMARY KEY, btree (book_id) Referenced by: TABLE "loans" CONSTRAINT "loans_book_id_fkey" FOREIGN KEY (book_id) REFERENCES books(book_id) library=# \\d loans; Table "public.loans" Column | Type | Collation | Nullable | Default -------------+---------+-----------+----------+---------------------------------------- loan_id | integer | | not null | nextval('loans_loan_id_seq'::regclass) book_id | integer | | | loan_date | date | | not null | return_date | date | | | Indexes: "loans_pkey" PRIMARY KEY, btree (loan_id) Foreign-key constraints: "loans_book_id_fkey" FOREIGN KEY (book_id) REFERENCES books(book_id) library=# # Default 값에 내용이 추가되었다.
# 파이썬 실행 상황 도서 입력 기능 실행! 새로운 도서를 추가합니다. 도서 제목을 입력하세요 : 제목 저자를 입력하세요 : 저자 출판사를 입력하세요 : 출판사 도서가 추가되었습니다. # psql 에서 조회 library=# SELECT * FROM books; book_id | title | author | publisher | is_available ---------+-------+--------+-----------+-------------- 1 | 제목 | 저자 | 출판사 | t (1 row) library=# SELECT * FROM loans; loan_id | book_id | loan_date | return_date ---------+---------+-----------+------------- (0 rows) library=# # 한글, 영어, 숫자 모두 정상적으로 입력 됨 library=# SELECT * FROM books; book_id | title | author | publisher | is_available ---------+--------+--------+-----------+-------------- 1 | 제목 | 저자 | 출판사 | t 2 | ㅁㄴㄹ | asfa | qwd | t 3 | 1111 | 2222 | 3333 | t (3 rows) library=#
# psql 에서 직접 제거 명렁어 실행 DROP TABLE books; DROP TABLE loans; # 파이썬 코드에서 INTEGER 로 만들었던 내용을 SERIAL 로 변경 cursor.execute(""" CREATE TABLE IF NOT EXISTS books ( book_id SERIAL PRIMARY KEY, title VARCHAR(100) NOT NULL, author VARCHAR(50) NOT NULL, publisher VARCHAR(50) NOT NULL, is_available BOOLEAN NOT NULL DEFAULT TRUE ); """) # loans 테이블 채크후 없으면 생성 cursor.execute(""" CREATE TABLE IF NOT EXISTS loans ( loan_id SERIAL PRIMARY KEY, book_id INTEGER, loan_date DATE NOT NULL, return_date DATE, FOREIGN KEY (book_id) REFERENCES books (book_id) ); """)
- cursor.execute("""INSERT INTO books (title, author, publisher) VALUES (%s, %s, %s);""", (title, author, publisher,)) psycopg2.errors.NotNullViolation: null value in column "book_id" of relation "books" violates not-null constraint DETAIL: Failing row contains (null, 한글로하면?, 되나?, 진짜로?, t).
최종 수정된 insert_book()
def insert_book(): # 파일로 추가하는 부분은 나중에
connection = psycopg2.connect(host=DATABASE_HOST, user=DATABASE_USER, password=DATABASE_PASSWORD,
dbname=DATABASE_NAME, port=DATABASE_PORT)
cursor = connection.cursor()
print("새로운 도서를 추가합니다.\\n")
title = input("도서 제목을 입력하세요 : ")
author = input("저자를 입력하세요 : ")
publisher = str(input("출판사를 입력하세요 : "))
cursor.execute("""INSERT INTO books (title, author, publisher) VALUES (%s, %s, %s);""", (title, author, publisher,))
connection.commit()
print("\\n도서가 추가되었습니다.\\n")
print("DB close executed")
cursor.close()
connection.close()
print("DB close done")
입력 기능 추가된 main()
def main():
create_connection()
try:
while True:
option = start_page()
if option == 1:
print("\\n")
print("도서 입력 기능 실행!")
print("\\n")
insert_book()
elif option == 2:
print("\\n")
print("도서 검색 기능 실행!")
print("\\n")
search_book()
elif option == 3:
pass
elif option == 4:
pass
elif option == 5:
pass
elif option == 6:
print("\\n")
print("시스템을 종료합니다.")
print("\\n")
break
else:
print("error")
except ReturnToMainMenu:
main()
except ExitProgram:
print("\\n")
print("시스템을 종료합니다.")
print("\\n")
728x90
반응형
'Dev. > Python' 카테고리의 다른 글
Python : functools.cmp_to_key() (0) | 2023.10.17 |
---|---|
Python - Mini project : Library Management System 4 (0) | 2023.07.20 |
Python - Mini project : Library Management System 2 (1) | 2023.07.19 |
Python - Mini project : Library Management System 1 (0) | 2023.07.19 |
Python - 배열 (1) | 2023.06.13 |
댓글