Conversation
| <Route path="/users/add" element={<AddUserPage />} /> | ||
| <Route path="/users/:id" element={<UserPage />} /> | ||
| <Route path="/users/edit/:id" element={<EditUserPage />} /> | ||
| </Routes> |
| import PropTypes from 'prop-types'; | ||
| import Sidebar from './Sidebar'; | ||
| import CustomHeader from './CustomHeader'; | ||
| //import UserPage from '../pages/UserPage'; |
| <Router> | ||
| <AppLayout> | ||
| <Routes> | ||
| <Route path="/" element={<UserListPage />} /> |
There was a problem hiding this comment.
사용자 목록 페이지의 라우팅 path를 root로 지정한 이유
| <AppLayout> | ||
| <Routes> | ||
| <Route path="/" element={<UserListPage />} /> | ||
| <Route path="/users/add" element={<AddUserPage />} /> |
| @@ -0,0 +1,44 @@ | |||
| // // src/components/Header.jsx | |||
|
|
||
| const CustomHeader = () => { | ||
| return ( | ||
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
| <Sidebar /> | ||
| </Sider> | ||
| <Layout> | ||
| <Header style={{paddingTop: '12px', background: '#fff'}}> |
There was a problem hiding this comment.
Header child로 CustomHeader가 있어 중첩된 Header 구조가 되어 있음 CustomHeader가 Header를 대체하는 것이 좋을 듯
| trigger={null} | ||
| className="sider" | ||
| style={{ | ||
| height: '100vh', |
| const navigate = useNavigate(); | ||
| const items=[ | ||
| {key: '1', label: 'Dashboard'}, | ||
| {key: '2', label: '메일링'}, |
| ); | ||
| }; | ||
|
|
||
| export default UserSearchFilter; |
| setSearchValue(e.target.value); | ||
| } | ||
|
|
||
| const handleSearch = () => { |
There was a problem hiding this comment.
없는 이름으로 검색 후 초기화 하지 않으면 검색 기능이 동작하지 않음
| response = None | ||
| if not response: | ||
| response = self.get_response(request) | ||
| if hasattr(self, 'process_response'): |
There was a problem hiding this comment.
process_response가 내부적으로 구현되어 있는지 체크가 정말 필요한지
| 'message': None | ||
| } | ||
|
|
||
| if hasattr(response, 'data') and getattr(response, 'data') is not None: |
There was a problem hiding this comment.
walrus operation과 getattr default 옵션을 사용하면 좋을 것 같습니다.
예시) if response_data := getattr(response, "data", None):
| } | ||
|
|
||
| useEffect(() => { | ||
| const fetchUser = async () => { |
There was a problem hiding this comment.
Jotai나 hook을 사용해서 관리하면 좋을 것 같습니다.
| class UserViewSet(viewsets.ModelViewSet): | ||
| queryset = User.objects.all().order_by('id') | ||
| serializer_class = UserSerializer | ||
| filter_backends = [SearchFilter, DjangoFilterBackend] |
There was a problem hiding this comment.
퍼블릭하게 사용할 필터 백엔드는 settings.py에 DEFAULT_FILTER_BACKENDS 옵션으로 관리하면 좋습니다.
| class UserSerializer(serializers.ModelSerializer): | ||
| class Meta: | ||
| model = User | ||
| fields = ['id', 'username', 'email', 'password', 'is_active', 'is_admin'] |
| ) | ||
| email = models.EmailField(unique=True) | ||
| password = models.CharField( | ||
| max_length=16, |
There was a problem hiding this comment.
Django에서는 패스워드 저장할 때 해싱하여 저장하기 떄문에 글자 수가 16글자를 넘습니다.
migration 파일 보시면 max_length가 128로 설정되어 있습니다.
| """ | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
| class ResponseFormattingMiddleware: |
There was a problem hiding this comment.
응답에 대한 formatting은 일반적으로 middleware보단 view / viewset에서 하는 편입니다.
Backend
{ "success": false, "result": null, "message": { "password": [ "password must be ..." ] } }Frontend