09월01일 (화)

Win Cha·2026년 9월 2일

오늘도 CLI 게시판 프로그램 코드 작성..

기능 구현 : 생성,지우기, 목록보기, 수정 / 할일 => 회원 개념

회원 개념 : 회원 신청(id/pw) 코드 완료(10시 30분) -> 관리(승인) 후 게시글 등록, 수정, 삭제가능

관리(admin 계정) : 회원 신청 승인, 회원(목록) 보기 (수정, 삭제)

로그인(log in) 명령어 실행 후 id / pw 승인 후 권한 획득 후 게시판 글 생성 가능 (코드 완성: 10시 50분)

print("-" 21)
print("== CLI 게시판 실행 ==")
print("-"
21)

from datetime import datetime #작성일시를 위한 함수 호출
num = 0
articles = [] # 게시글들용 딕셔너리 입니다.
users = [] # 회원들용 딕셔너리 입니다.

while True: # 참인 동안 아래 실행 ('exit' 입력 시 종료)

print("명령어 입력 = 회원'log in', 비회원 'user join'") # (비)회원 명령어

cmd = input("명령어 )")  #명령어 입력

if cmd == "exit":  #종료 명령
   print("== CLI 게시판 종료 ==")
   break

elif cmd == "log in":  # 회원 인증
    count = 0

    while True:  # 참인 동안 아래 실행 ('exit' 입력 시 종료)

      revise_id = input("사용자 id를 입력하세요: ")
      revise_pw = input("사용자 pw를 입력하세요: ")

      # id 목록에 없는 경우 검증용 스위치.
      is_revised = False

      for id in uers:
        # 꺼내온 글상자의 'id' 번호가 사용자가 입력한 revise_id와 일치하는지 검사합니다.
        if users["id"] == revise_id & users["pw"] == revise_pw :

          # 글생성 확인
          print(f"{revise_id}님이 로그인 되었습니다.\n")
          is_revised = True  # 수정 후 찾았다고 스위치 참으로 변경
          break

      if is_revised == False:
        print(f"{revise_id}는 회원 아니거나 비번이 틀립니다. 다시 입력 \n")


elif cmd == "user join":  # 회원 가입
  id = input("회원ID : ")
  pw = input("비밀번호 : ")
  nickname = input("별명 : ")
  now_time = datetime.now().strftime("%Y년%m월%d일 %H시%M분%S초")

  #게시글 작성 (시간을 자동 등록)
  article_data = {
    "id": id,
    "pw": pw,
    "nickname": nickname,
    "date": now_time
  }

  # 코드 실행 시 게시물이 추가 누적
  articles.append(article_data)

  # 글생성 확인
  print(f"{id}님의 회원 신청이 완료 되었습니다.\n")

else:
     print("지원하지 않는 명령어 입니다.\n")

while True: # 참인 동안 아래 실행 ('exit' 입력 시 종료)
cmd = input("명령어 )") #명령어 입력

if cmd == "exit":  #종료 명령
   print("== CLI 게시판 종료 ==")
   break

elif cmd == "a w":  # article write: 게시글 작성
    num += 1
    title = input("제목 : ")
    content = input("내용 : ")
    now_time = datetime.now().strftime("%Y년%m월%d일 %H시%M분%S초") #추천 regDate

    #게시글 작성 (시간을 자동 등록)
    article_data = {
        "id": num,
        "title": title,
        "content": content,
        "date": now_time
    }

    # 코드 실행 시 게시물이 추가 누적
    articles.append(article_data)

    # 글생성 확인
    print(f"{num}번 글이 생성 되었습니다.\n")

elif cmd == "a l":  # article list: 전체 목록 보기
    print("=" * 40)
    print("번호/ 제목       / 내용")

    # 딕셔너리에 저장된 게시글 출력
    for art in articles[::-1]:
      print(f"{art['id']}   / {art['title']} / {art['content']}")
    print("=" * 40)

elif cmd == "a v":  # article detail view: 게시글의 상세보기
     dread_id = int(input("상세보기 할 글 id 번호를 입력하세요: "))
     is_dreaded = False

     for art in articles:
        # 선택 'id' 번호가 딕셔너리에 있는지 확인
        if art["id"] == dread_id:
           print (f"게시글 No: {art['id']}")
           print (f"제 목 : {art['title']}")
           print (f"내 용 : {art['content']}")
           print (f"작성일시 : {art['date']}")
           is_dreaded = True  # 해당 글 찾았다고 스위치 참으로 변경
           break

     if is_dreaded == False: #목록에 번호에 없다고 출력
       print(f"{dread_id}번 글은 목록에 없습니다.\n")

elif cmd == "a d":  # delete article list (선택 삭제)
    delete_id = int(input("삭제할 글 id 번호를 입력하세요: "))

    # 목록 없음 구분자
    is_deleted = False

    for art in articles:
        # 꺼내온 글상자의 'id' 번호가 사용자가 입력한 delete_id와 일치하는지 검사합니다.
        if art["id"] == delete_id:
            articles.remove(art)
            print(f"{delete_id}번 글이 삭제되었습니다.\n")
            is_deleted = True  # 글을 성공적으로 찾아서 지웠다고 스위치를 켭니다.
            break              # 원하는 글을 지웠으므로 탐색 루프를 탈출합니다.

    # id 리스트에 없는 경우 실행.
    if is_deleted == False:
        print(f"{delete_id}번 글은 목록에 없습니다.\n")

elif cmd == "a r":  # article revise (선택 수정)
    revise_id = int(input("수정할 글 id 번호를 입력하세요: "))

    # id 목록에 없는 경우 검증용 스위치.
    is_revised = False

    for art in articles:
        # 꺼내온 글상자의 'id' 번호가 사용자가 입력한 revise_id와 일치하는지 검사합니다.
        if art["id"] == revise_id:
          title = input("제목 : ")
          content = input("내용 : ")

          art["title"] = title
          art["content"] = content

          # 글생성 확인
          print(f"{revise_id}번 글이 성공적으로 수정 되었습니다.\n")
          is_revised = True  # 수정 후 찾았다고 스위치 참으로 변경
          break

    if is_revised == False:
       print(f"{revise_id}번 글은 목록에 없습니다.\n")

else:
  print("지원하지 않는 명령어 입니다.\n")

9월01일 16시 40분 : 강사님 강의로 클래스 활용 코드

from datetime import datetime
from dataclasses import dataclass # 파이썬에서 데이터를 담는 클래스를 쉽게 만들도록 도와주는 도구입니다.

==========================================

1. 클래스 (데이터 설계도) 정의

==========================================

init (초기화) 함수를 뒷단에서 자동으로 만들어줍니다.

덕분에 코드가 훨씬 짧고 직관적으로 변합니다. 변수명과 자료형(int, str)만 적어주면 끝입니다.

@dataclass
class Article:
id: int # 글 번호 (정수)
regDate: str # 작성일 (문자열)
updateDate: str # 수정일 (문자열)
title: str # 제목 (문자열)
body: str # 내용 (문자열)

기존에 우리가 직접 타이핑해야 했던 길고 복잡한 클래스 세팅 과정(아래 부분)을

class Article:

def init(self, id, regDate, updateDate, title, body):

# 생성자 -> 글 하나가 만들어질 때 자동으로 호출되는 함수

# self -> 지금 만들어지는 바로 그 글 자신

self.id = id

self.regDate = regDate

self.updateDate = updateDate

self.title = title

self.body = body

==========================================

2. 공통 함수 모음

==========================================

def now():

# 현재 시각을 "YYYY-MM-DD HH:MM:SS" 형태의 문자열로 만들어 반환합니다.
return datetime.now().strftime("%Y-%m-%d %H:%M:%S") #strftime = String Fomat Time

def parse_id(cmd):

# 사용자가 "article delete 3" 이라고 쳤을 때, 맨 뒤의 숫자 '3'만 안전하게 뽑아내는 함수입니다.
cmdBits = cmd.split(" ")
if len(cmdBits) < 3:
    print("명령어를 확인해주세요(길이 모자람)")
    return None
if not cmdBits[2].isdigit():
    print("명령어를 확인해주세요(번호대신 str 입력)")
    return None
return int(cmdBits[2])

def find_article(articles, article_id):

# 게시글 목록(articles)을 처음부터 끝까지 뒤지며, 내가 찾는 id와 일치하는 글을 찾아 돌려줍니다.
for article in articles:
    # [핵심] 딕셔너리일 때는 article["id"] 였지만, 이제 클래스 객체이므로 점(.)을 찍어 article.id 로 접근합니다.
    if article.id == article_id:
        return article
return None

def format_date(regDate):

# 오늘 작성된 글이면 시간(12:12:12)만, 예전 글이면 날짜(2025-12-12)만 보여주는 센스 있는 포맷팅 함수입니다.
today = now().split(" ")[0]        
datePart = regDate.split(" ")[0]   
timePart = regDate.split(" ")[1]   
if datePart == today:
    return timePart
else:
    return datePart

def makeTestData():

프로그램 시작 시 텅 비어있으면 심심하니, 미리 Article 클래스(틀)를 이용해 붕어빵(객체) 3개를 구워둡니다.

딕셔너리 기호 {} 대신 Article(값, 값, ...) 형태로 소괄호를 사용하여 객체를 생성합니다.

return [
Article(1, "2025-12-12 12:12:12", "2025-12-12 12:12:12", "제목1", "내용1"),
Article(2, now(), now(), "제목2", "내용2"),
Article(3, now(), now(), "제목3", "내용3")
]

==========================================

3. 메인 프로그램 시작

==========================================

print("== CLI 게시판 실행 ==")

last_article_id = 3
articles = makeTestData() # 위에서 만든 객체 3개를 게시글 가방(리스트)에 담습니다.

while True:
cmd = input("명령어 ) ").strip()

if cmd == "exit":
    break

elif cmd == "article write":
    last_article_id += 1
    title = input("제목 : ")
    body = input("내용 : ")
    
    # [핵심] 딕셔너리를 만들던 코드 대신, Article 클래스를 불러와 새로운 객체를 한 줄로 뚝딱 만듭니다.
    article = Article(last_article_id, now(), now(), title, body)
    articles.append(article)
    print("{}번 글이 생성되었습니다".format(last_article_id))

elif cmd == "article list":
    if not articles:
        print("게시글이 없습니다")
    else:
        print("=========================================")
        print("   번호      /     제목       /     내용   /     작성일   ")
        for a in reversed(articles):
            # 객체의 속성을 꺼낼 때는 a["title"] 이 아니라 a.title 처럼 마침표(.)를 사용합니다.
            print("   {}      /     {}       /     {}          /     {}   ".format(
                a.id, a.title, a.body, format_date(a.regDate)))
        print("=========================================")

elif cmd.startswith("article delete"):
    deletedId = parse_id(cmd) # 공통 함수로 숫자만 빼옵니다.
    if deletedId is None: continue

    article = find_article(articles, deletedId) # 공통 함수로 지울 객체를 통째로 찾아옵니다.
    if article is None:
        print("{}번 글은 없습니다".format(deletedId))
        continue

    articles.remove(article) # 리스트에서 그 객체를 날려버립니다.
    print("{}번 글이 삭제되었습니다".format(deletedId))

elif cmd.startswith("article edit"):
    editedId = parse_id(cmd)
    if editedId is None: continue

    article = find_article(articles, editedId)
    if article is None:
        print("{}번 글은 없습니다".format(editedId))
        continue

    # 객체 안의 기존 값을 보여주고,
    print("기존 제목 : {}".format(article.title))
    print("기존 내용 : {}".format(article.body))
    
    # 입력받은 새로운 값을 객체의 속성에 바로 덮어씌웁니다.
    article.title = input("새 제목 : ")
    article.body = input("새 내용 : ")
    article.updateDate = now()
    print("{}번 글이 수정되었습니다".format(editedId))

elif cmd.startswith("article detail"):
    detailId = parse_id(cmd)
    if detailId is None: continue

    article = find_article(articles, detailId)
    if article is None:
        print("{}번 글은 없습니다".format(detailId))
        continue

    # 마침표(.)를 이용해 객체가 가진 모든 데이터를 쏙쏙 뽑아 출력합니다.
    print("번호 : {}".format(article.id))
    print("작성 날짜 : {}".format(article.regDate))
    print("수정 날짜 : {}".format(article.updateDate))
    print("제목 : {}".format(article.title))
    print("내용 : {}".format(article.body))

else:
    print("지원하지 않는 기능입니다")

print("== CLI 게시판 종료 ==")

0개의 댓글