목록으로

할 일 그룹 목록 구현

시리즈, 입문
2024. 7. 3. AM 10:25:31

기본 구현

임시로 구현한 할 일 그룹 목록 페이지를 정식으로 구현해볼게요.

(1) TodoGroupService에 findall() API 구현

할 일 그룹을 조건에 맞게 검색하는 API인 findall() 메서드를 TodoGroupService 에 구현할게요. 최소한으로 필요한 검색 조건은 바로 특정 사용자지요.
Result 객체의 scalars() 를 사용하고, ScalarResult 객체의 all() 메서드를 사용한 점을 제외하면 기존 select() 구문 생성 및 데이터 질의(querying) 구현과 다르지 않아요. 질의 결과가 복수 개이므로 스칼라 값을 scalars() 로 가져오고, 가져온 스칼라 값 모두를 가져온 것이지요. 만약 데이터가 매우 많다면 파티셔닝( partitions() )이나 페이징(Paging) 기법을 쓰는 게 좋아요.
구현한 코드 커밋 : afee423

(2) 할 일 그룹 목록 페이지 종단점 함수 구현

앞서 임시로 작성한 코드에 findall() 로 할 일 그룹 목록을 가져오는 구현을 추가했어요. 간단하죠?
구현한 코드 커밋 : 17febca

(3) 할 일 그룹 목록 출력

데이터베이스에서 할 일 그룹 목록을 가져왔으니 todo-group-list.jinja2 템플릿 파일을 수정해 할 일 그룹 목록을 나열해볼게요.
잘 동작하죠? 이제 좀 모양이 나오네요! 😀
작성한 코드 커밋 : 2f4cd5c

비동기로 할 일 그룹의 할 일 개수 가져와 표시하기

(1) htmx로 지연 로딩과 부분 렌더링 구현

할 일 그룹명을 출력하고 그 옆에 해당 그룹에 존재하는 할 일 개수를 출력했는데요. 이 코드는 데이터베이스에 부하를 일으키는 동작을 할 가능성이 커요. 단순히 개수만 표시하면 되는데, group.todos|length 는 데이터베이스에서 해당 할 일 그룹에 관계 맺은 할 일 데이터를 모두 가져온 후 Python 영역에서 개수를 세기 때문이죠. 불필요한 데이터를 모두 가져오는 부분에서 한 번, 그리고 Python에서 데이터 개수를 세는 부분에서 또 한 번 성능 저하가 일어나는 거예요.
이 부분을 htmx로 단순한 방식으로 개선해볼게요. 방식은 다음과 같아요.
  1. 할 일 그룹 목록 페이지에 접속
  2. 할 일 그룹 이름이 화면에 표시되면
  3. 각 할 일 그룹 별로 할 일 개수를 출력하는 API를 비동기로 호출
  4. 호출 결과를 할 일 그룹 이름 옆에 표시
htmx를 이용하면 아주 간단하게 구현할 수 있어요. 먼저 pages/todo-group-list.jinja2 템플릿을 수정해 htmx 구현을 적용할게요.
htmx 코드 두 줄만으로 네 단계를 구현했어요. hx-trigger="load delay:250ms" 는 해당 HTML Dom 요소가 화면에 드러나면 0.25초 후에 작업을 수행하는 거예요.
htmx가 "partial-todo-group-todos-count" 라 이름붙은 URL을 호출해요. 이 HTTP API를 구현해야겠어요.
@tpl.hx() 장식자가 새롭게 등장했어요. hx() 장식자는 FastHX에서 제공하는 메서드로, htmx 요청인 HTTP Request만 허용해요. 이런 설정이 page() 장식자엔 없어요.

(2) 할 일 그룹 별 할 일 개수 가져오기

TodoService count_by_group_id() API를 새롭게 추가해야 해요. 이름 그대로 할 일 그룹 ID(기본키 값)으로 할 일 개수를 세는 동작을 하죠. 근데 남의 할 일 그룹 ID를 알면 남의 할 일 개수도 알아낼 수 있잖아요? 그래서 이 API를 호출하는 사용자의 ID(기본키값)도 데이터 질의 검색 조건에 추가할 거예요.
조금 생소할 수 있는데, 다음 SQL 질의문을 작성하는 코드예요.
참고로 의사 코드이며, 실제로 작성하는 SQL문은 다음과 같아요.
SQL count(*) 에 해당하는 Python 코드가 func.count() 에요. SQLAlchemy에서 제공하는 func 객체는 Function API 인데, SQL 함수 구문을 생성해주지요.
Todo.group 모델 필드는 TodoGroup 모델에 대한 관계 필드예요. 자료형 각주와 달리 TodoGroup 모델 그 자체는 아니예요. 그래서 Todo.group.user_id == user_id 표현식을 사용하지 못하는데, SQLAlchemy는 has() 로 관계 필드에 대한 탐색(lookup) 연산을 수행해줘요. Todo.group.has(TodoGroup.user_id == user_id) 는 다음 SQL문을 작성하지요.
개수를 셋으니 이를 템플릿으로 출력합니다. pudding_todo/apps/todo/templates 디렉터리 안에 부분이라는 뜻으로 partial 디렉터리를 만들고, 이 디렉터리 안에 todo-group-todos-count.jinja2 파일로 템플릿을 만들어요.
페이지 렌더링 템플릿은 pages 디렉터리에, 부분 렌더링 템플릿은 partial 디렉터리에 배치한 거죠.
여기까지 진행한 코드 커밋 : 33fdfc1
목차