티스토리 뷰
곧바로 N:1에 대해서 배워보자. 전에 배웠다시피 게시글과 댓글은 N(댓글):1(게시글) 관계를 갖고 있다. 이미 REST API가 아니더라도 다뤄본 내용의 반복이 대부분이기 때문에 쉽게 따라올 수 있을 것이다. 마찬가지로 comment 도 serializer 사용해주어야 한다. 주의해야 할 부분은 ForiegnKey 부분이니 집중해서 따라가보자..
먼저 데이터를 load할 예정이기 때문에 모델을 먼저 작성해주려고 한다. 데이터가 없다면 model을 작성 후에 admin으로 작성해주어도 되고, 매크로를 사용해도 된다.
만들어야 할 HTTP request method 구성을 표로 나타내보고 하나씩 클리어 해보자!
URL | GET | POST | PUT | DELETE |
comments/ | 댓글 목록 조회 | |||
comments/ <int:comments_pk>/ |
단일 댓글 조회 | 단일 댓글 수정 | 단일 댓글 삭제 | |
articles/<int:articles_pk>/ comments/ |
댓글 생성 |
GET comment List
사실 게시글에 해당하는 댓글을 보는 것이 아니라 다른 게시글에 쓰인 댓글 까지 한번에 조회하는일이 자연스럽지는 않지만
가장먼저 해야할 것은? serializers 작성!
이제 머릿속에 django 흐름을 기억하고 있기 때문에 부드럽게 작성 과정이 이어져야 한다. 또, 이제 어느 부분에 import 해야 가져와서 쓸 수 있는지 알 것 이기 때문에 특별한 import 제외하고는 캡쳐하지 않으려 한다.
GET comment
클라이언트 입장에서는 detail 페이지에서 보는 것과 동일하므로 url를 나누어주고, comment_pk를 명시해주어야 Comment QuerySet에서 데이터를 특정하여 조회할 수 있다. 이젠 익숙하지 않은가?
POST comment 생성
comment를 생성하는 과정은 article의 detail 페이지에서 진행되는 것이 자연스럽고, comment에 ForiegnKey인 article이 존재하기 때문에 반드시 article의 pk 값이 전달되어야 한다. 주의하면서 작성해볼까? serializers는 이미 만들어진 것을 활용할 수 있다.
이전에 django의 form을 다루면서 N:1 과정에서 ForiegnKey에 대해 수동으로 넣어줘야하는 것을 기억할 것이다. 조금 다른점은 serializer의 save() method는 commit=False를 이용하지 않고, 인자를 다이렉트로 넣어줄 수 있다.
잘 생각해보자. CommentSerializer를 째려보면 model은 Comment이며, fields 역시 '__all__'로 정의되어있다. 그럼 애초에 request.data에 article의 pk가 안담겨있는데, CommentSerializer()를 통과할 수 있었을까? 아닐 것이다. 그렇다면 정의되어있지 않는 Comment 모델의 article을 보류해야하는데, 이때 '읽기 전용' 을 이용할 수 있다.
읽기 전용 필드(read_only_fields)
읽기 전용은 word, excel 등에서도 사용되는 것을 볼 수 있다. 사용자는 읽기만 가능하고 데이터 생성, 수정, 삭제가 불가능한 파일을 의미한다. serializer에서도 유사한 역할을 해주는데, 필드를 지정해서 읽기 속성을 부여한다면, 유효성 검사에서 검사 항목에서 빠지게 된다. 그럼 출력은 ? 읽기 전용이라면 당연히 출력은 가능할 것 같지 않은가?
DELETE comment 삭제
삭제는 게시글 삭제와 동일하기 때문에 간단하다. 단일 comment 데이터를 불러와 삭제 하기만 하면 된다.
PUT comment 수정
수정은 항상 주의해야할 점인 이전 데이터를 호출해줘야하는 것만 주의하면 create와 동일하다.
참고로 수정의 경우 instance에 article이 연결되어 있기 때문에 save하면서 넣어줄 필요는 당연히 없다.
이렇게하여 comment의 CRUD까지 모두 완료되었다. 하지만 우리가 데이터를 조회할 때, 혹은 api를 전달 받을 때 한번에 데이터를 가공할 수 있으면 API 데이터 활용에 이점이 있지 않을까?
심화 : 응답 데이터 재구성
comment 조회 시 article의 정보 제공하기
: 필요한 데이터를 만들기 위한 Serializer는 내부에서 추가 선언이 가능하다
Article 조회 시 Comment의 정보 제공하기
위에서는 Comment와 Article이 참조 관계를 이용했고, Article에서는 Comment를 호출할 방법이 없다. 이때 사용하는 것은 전에 배웠던 것처럼 역참조 매니저를 활용한다.
Nested relationships (역참조 매니저 활용)
: 모델 관계 상으로 참조하는 대상은 참조되는 대상의 표현에 포함되거나 중첩될 수 있다
: 중첩 관계는 serializers를 필드로 사용하여 표현 가능하다
: 앞서 정의된 Serializer를 이용하므로 순서가 중요하다
: 역참조 하는 객체의 fields에 포함되는 것이므로 exclude 혹은 fields 정의를 확인 한다
- 해당 게시글의 작성된 댓글 목록을 포함하여 응답
- 해당 게시글의 작성된 댓글 개수를 포함하여 응답
역참조를 통해 comment_set을 정의했기 때문에, 호출한 데이터를 직접 가공하여 정의할 수 있다. 이때, serializers에서 ModelField를 추가하는 것과 유사하며, 내부 데이터는 인자로 source를 통해 집어 넣을 수 있다.
'source' arguments
- 필드를 채우는데 사용할 속성의 이름
- 점 표기법(dotted notation)을 사용하여 속성을 탐색 할 수 있다
주의사항
읽기 전용 필드 지정관련해서 read_only_fields를 따로 지정하지 않고 필드가 추가될 때 read_only=True를 설정해주었다. 이는 특정 필드를 override 혹은 추가했을 때, read_only_fields로는 동작하지 않기 때문이다.
+ 부록
Django shortcuts functions
: django에서 제공해주는 shortcuts 함수로, 기존에 사용하던 방식에서는 서버 오류 발생 raise인 Http500에서 원인을 정확하게 파악하기 어렵다. 따라서 어느 지점에서 에러가 발생했고, 정확한 에러 현황을 전달하는 것도 매우 중요한 개발 요소 중 하나이기 때문이다.
get_object_or_404() | get_list_or_404() |
모델 manager objects에서 get()을 호출하지만, 해당 객체가 없다면 기존 DoesNotExist 예외 에러 대신 Http404 에러를 raise |
모델 manager objects에서 filter()의 결과를 반환하고, 해당 객체 목록에 없을 때 Http404 에러를 raise |
드디어 rest api가 끝났다. 사실 N:1까지는 할만한데, N:M이 많이 어렵다. 잠깐 맛보기했는데 맛없다. 오늘도 수고했다!
'일상코딩 > 노트' 카테고리의 다른 글
javascript : BasicSyntax (3) | 2024.04.17 |
---|---|
JavaScript : DOM (3) | 2024.04.16 |
Django : REST API 2 (1) | 2024.04.12 |
Django : REST API 1 (0) | 2024.04.11 |
Django : Many to one relationship (2) | 2024.04.05 |
- Total
- Today
- Yesterday
- baby-gin
- JavaScript
- SQLite
- Component
- Django
- ChatGPT
- HTML
- refactoring
- basic syntax
- views.py
- honeymoney
- 재귀
- 연산자
- CodeTree
- dfs
- Sequence types
- 순열
- 카운팅정렬
- vue
- 백준
- Database
- Python
- ssafy
- 삼성청년SW아카데미
- Authentication System
- app
- SQL
- 함수
- Method
- vue3
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |