Skip to content

feat: 사용자 관리 화면 구현#2

Open
ysbeam wants to merge 2 commits intojungmir:masterfrom
ysbeam:soyoung
Open

feat: 사용자 관리 화면 구현#2
ysbeam wants to merge 2 commits intojungmir:masterfrom
ysbeam:soyoung

Conversation

@ysbeam
Copy link

@ysbeam ysbeam commented Oct 2, 2024

이슈 한 줄 요약

사용자 관리 화면, API 구현

상세 작업 내용

[frontend]

  • jotai를 활용하여 서버 스테이트 관리
  • msw 사용하여 서버 mocking
  • antd 라이브러리를 사용하여 UI 구성

필요 기능 목록

  • 전체 목록 조회 페이지(검색 필터, 정렬) 구현
  • 수정, 추가 페이지 필드별 유효성 검사
  • 사용자 삭제
  • 에러, 성공 메시지

[backend]

  • DRF의 컴포넌트(ViewSet, Serializer 등)를 사용하여 기능 구현
  • Middleware를 사용하여 에러 및 예외 처리
  • 구현한 API에 대한 테스트 코드 작성
  • 로깅, 로그 파일 관리(로테이션), DB 저장

필요 API 목록

  • 전체 사용자 목록 조회(검색 필터링, 페이지네이션)
  • 특정 사용자 조회(수정, 삭제)
  • 공통(에러 및 예외처리)

참고사항

  • 전체 사용자 목록 조회: http://127.0.0.1:8000/api/users
  • 특정 사용자 조회: http://127.0.0.1:8000/api/users/{id}
  • 특정 검색 필터링 조회: http://127.0.0.1:8000/api/users/?search=ys
  • 특정 페이지 조회: http://127.0.0.1:8000/api/users/?page={pagenum}

<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible>
<div className="logo" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['2']}>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultSelectedKeys가 하드코딩되어 있어 다른 페이지에서 새로 고침 했을 때 활성화 메뉴가 현재 페이지랑 안맞는 이슈가 있습니다.

<Content style={{ padding: '20px 50px', marginTop: 64, flex: '1 1 auto' }}>
<Routes>
<Route path="/users" element={<UserList />} />
<Route path="/add" element={<UserAdd />} />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용자 추가 화면으로 이동하는데 라우팅이 /users/add가 아닌 이유가 있을까요?

<Route path="/add" element={<UserAdd />} />
<Route path="/edit/:id" element={<UserEdit />} />
<Route path="/" element={<div>Dashboard Section</div>} />
<Route path="/posts" element={<div>Posts Section</div>} />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요구 사항에 없는 페이지와 라우팅은 없어도 괜찮습니다.


<Layout>
<Header style={{ padding: 0, background: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div style={{ marginLeft: '20px', display: 'flex', alignItems: 'center' }}>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

div 대신 Space나 Flex 컴포넌트를 사용하면 더 좋을 것 같습니다.


//사용자 목록 가져옴
useEffect(() => {
fetch('/api/users')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jotai나 hook을 사용하여 관리하는 것이 일반적입니다.

dataIndex: 'id',
key: 'id',
sorter: (a, b) => a.id - b.id,
sortOrder: sortedInfo.columnKey === 'id' && sortedInfo.order,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sortOrder가 없어도 문제 없을 것 같은데 명시하신 이유가 있을까요?

headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedUser),
});
if (!res.ok) throw new Error('Failed to update user');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mock 서버에 데이터가 없어서 404 error가 발생합니다.

}

.ant-layout-header {
position: fixed;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 옵션으로 아바타 컴포넌트가 안보이는 경우가 생깁니다.

const onFinish = async (values) => {
try {
const updatedUser = { ...selectedUser, ...values };
const res = await fetch(`/api/users/${id}`, {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

await 사용보단 then(), catch()를 사용하여 처리하는 걸 권장합니다.

execute_from_command_line(sys.argv)


if __name__ == '__main__':
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user_management 프로젝트는 왜 만들어진 건가요?

page_size_query_param = 'page_size'
max_page_size = 100

class UserViewSet(viewsets.ModelViewSet):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update, destroy 함수를 직접 구현해서 사용한다면 ModelViewSet을 상속하지 않아도 될 것 같습니다.

from django.http import HttpResponse

User = get_user_model()
def home_redirect(request):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

home_redirect 함수를 구현하신 특별한 이유가 있나요?

"""

import os
import logging
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미사용 import 구문은 제거하는 편이 좋습니다.

logger = logging.getLogger('users')

#페이지네이션 설정
class UserPagination(PageNumberPagination):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pagination 클래스는 별도 모듈로 빼면 더 좋을 것 같습니다.
추후 다른 app에서 사용가능

pagination_class = UserPagination

#검색 필터링 설정
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settings.py에서 기본 FilterBackend 클래스를 지정하는 옵션이 있습니다. 전체 API 대상으로 적용할 때는 이러한 방식을 주로 사용합니다.

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
groups = models.ManyToManyField(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 AbstractUser에 정의되어 있는 필드를 재정의 하신 이유가 있나요?


logger = logging.getLogger('users')

class CustomExceptionMiddleware:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 모듈은 user app이 아닌 프로젝트에 종속적이여서 모듈 위치가 config 하위로 가는게 좋아 보입니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants