반복되는 건 변수로
1. 이번 절의 목표
주소에 변수를 넣고, 데이터를 리스트에 모읍니다. 함수 세 개가 하나로 줄고, 게시물이 100개여도 함수는 하나입니다.
지난 절 끝에서 게시물 함수를 세 개 썼습니다. 같은 모양이 세 번 반복됐습니다. 프로그래밍에서 같은 것이 반복되면 답은 거의 정해져 있습니다. 반복되는 자리를 변수로 뺍니다.
| 지난 절 | 이번 절 |
|---|---|
/notice/1 → notice_1() | /notice/{id} → notice_detail(id) |
/notice/2 → notice_2() | (같은 함수) |
/notice/3 → notice_3() | (같은 함수) |
2. 주소에 변수 넣기
main.py에서 게시물 함수 세 개를 지우고 아래 하나로 바꿉니다.
@app.get("/notice/{id}", response_class=HTMLResponse)
def notice_detail(id: int):
return f"<h1>{id}번 게시물 입니다</h1>"
/notice/1, /notice/2, /notice/3을 다시 쳐 봅니다. 결과는 지난 절과 같습니다. 이번에는 /notice/100도 쳐 봅니다. 함수를 추가하지 않았는데 100번 게시물이 나옵니다.
무슨 일이 일어났는지 세 곳을 봅니다.
- 주소의
{id}: 중괄호로 감싼 자리는 "여기에 뭐가 오든 받아서id라는 이름에 담아라"는 뜻입니다. - 함수의
id: int: 주소에서 받은id를 함수가 넘겨받습니다.: int는 "정수로 바꿔서 달라"는 뜻입니다. f"...{id}...": 글자 안에id값을 끼워 넣습니다.
파이썬 다시 보기: f-string
f"안녕 {name}"처럼 따옴표 앞에 f를 붙이면, 중괄호 안의 변수가 값으로 바뀝니다. name이 "철수"면 "안녕 철수"가 됩니다. 이 책에서는 화면에 나갈 글자를 만들 때 계속 씁니다.
3. int의 힘
/notice/abc를 쳐 봅니다. 화면에 에러가 나옵니다.
{"detail":[{"type":"int_parsing", ... "Input should be a valid integer" ...}]}
id: int라고 써 두었기 때문에, 숫자가 아닌 것이 오면 FastAPI가 함수를 실행하기도 전에 막습니다. 우리가 검사 코드를 한 줄도 안 썼는데 검사가 됩니다. : int 두 글자가 한 일입니다. 이런 것이 도구를 쓰는 이유입니다.
4. 데이터를 리스트에 담기
지금은 게시물이 번호만 있고 내용이 없습니다. 내용을 넣으려면 어딘가에 담아야 합니다. 이 책에서는 파이썬 리스트에 담습니다.
main.py의 app = FastAPI() 아래에 데이터를 추가하고, 게시판과 게시물 함수를 아래처럼 바꿉니다.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
data = [
{'title': 'fastapi 너무 재미있어요! 1', 'contents': '첫 번째 글입니다.'},
{'title': 'fastapi 너무 재미있어요! 2', 'contents': '두 번째 글입니다.'},
{'title': 'fastapi 너무 재미있어요! 3', 'contents': '세 번째 글입니다.'},
]
@app.get("/", response_class=HTMLResponse)
def index():
return "<h1>hello world</h1>"
@app.get("/about", response_class=HTMLResponse)
def about():
return "<h1>about 입니다</h1>"
@app.get("/notice", response_class=HTMLResponse)
def notice():
result = ''
for i in data:
result += f'<p>{i["title"]}</p>'
return f"<h1>게시판 입니다</h1>{result}"
@app.get("/notice/{id}", response_class=HTMLResponse)
def notice_detail(id: int):
if id < 1 or id > len(data):
return "존재하지 않는 게시물입니다."
post = data[id - 1]
return f"""
<h1>게시물</h1>
<p>{post['title']}</p>
<p>{post['contents']}</p>
"""
/notice를 치면 제목 세 개가 나오고, /notice/2를 치면 두 번째 글의 제목과 내용이 나옵니다.
파이썬 다시 보기: 리스트와 딕셔너리
data는 리스트입니다. 대괄호 [ ] 안에 항목이 순서대로 들어 있고, data[0]이 첫 번째입니다. 순서는 0부터 셉니다.
각 항목은 딕셔너리입니다. 중괄호 { } 안에 '이름': 값 짝이 들어 있고, post['title']처럼 이름으로 꺼냅니다.
게시물 하나가 딕셔너리, 게시물 여러 개를 모은 것이 리스트입니다. 백엔드 데이터는 대부분 이 모양입니다.
data의 모양과 주소가 어떻게 연결되는지 그리면 아래와 같습니다.
주소의 번호는 1부터, 리스트의 칸은 0부터입니다. 그래서 코드에 id - 1이 있습니다.
5. 코드 읽기
새로 들어온 줄 몇 개를 읽습니다.
for i in data:: 리스트를 처음부터 끝까지 한 항목씩i에 담아 돕니다. 세 번 돕니다.result += ...: 돌 때마다<p>제목</p>을result뒤에 이어 붙입니다. 다 돌면<p>세 개가 붙은 글자가 됩니다.data[id - 1]: 1번 게시물은data[0]입니다. 사람은 1부터 세고 리스트는 0부터 세기 때문에 하나를 뺍니다.if id < 1 or id > len(data):: 0번이나 4번을 달라고 하면 리스트에 없습니다. 그냥 두면 서버가 에러를 내므로 먼저 막습니다.len(data)는 리스트의 길이, 지금은 3입니다.- 세 따옴표
""": 여러 줄짜리 글자를 만들 때 씁니다. HTML이 길어지면 이렇게 씁니다.
6. 여기까지의 그림
주소를 받고, 리스트에서 꺼내고, 글자로 만들어 돌려줍니다. 이것이 백엔드가 하는 일의 전부입니다. 나중에 리스트가 데이터베이스로 바뀌고, 글자가 예쁜 화면으로 바뀌어도 이 세 단계는 그대로입니다.
AI에게 물어보기
아래 코드에서 data[id - 1]에 왜 -1이 붙는지, 그리고 if id < 1 or id > len(data) 검사가 없으면 무슨 일이 생기는지 설명해줘.
(main.py 붙여넣기)
아래 코드의 data 리스트에 게시물을 두 개 더 추가해줘. 제목과 내용은 아무거나 재미있게.
(main.py 붙여넣기)
두 번째 프롬프트로 받은 코드를 붙여 넣으면 /notice에 제목이 다섯 개 나오고 /notice/5도 열립니다. 함수는 하나도 안 바꿨습니다. 데이터와 함수를 나눠 놓으면 이렇게 됩니다.