2021. 11. 12. 02:31ㆍ코딩일지/DRF

Django의 Views는?
크게 두 가지로 나눠서 Class based View와 Function based View가 존재하지만 두 가지의 차이는 쉽게 보자면 class를 사용한다와 method를 이용해 뷰를 만든다는 것인데 class views는 이후 mixin, generic views, viewset으로 진화? 되어간다고 보면 편하다.
class API views와 function views를 사용할수록 커스터마이징이 편리하고 자유도가 높아진다. 반대로 viewset으로 갈수록 규칙성이 높아진다. (만들어져 있는 기능을 그대로 사용하기 때문에)
저는 Fucntion > API views > Mixin > Generic views > Viewset 순으로 진행하겠습니다.
Django Function based View(FBV)란?
REST framework를 사용하면 일반 기능 기반 보기로 작업할 수도 있습니다.
함수 기반 뷰를 래핑 하여 Request(일반적인 Django 대신) 인스턴스를 수신하고 (Django 대신) HttpRequest 반환하도록 허용하고 요청 처리 방법을 구성할 수 있도록 Response 하는 간단한 데코레이터 세트를 제공합니다.
@api_view
1. 게시글과 댓글 모델링
게시글의 제목과 내용, 게시글의 댓글 내용을 만들기 위해 모델링을 진행하겠습니다.
- boards models.py
from django.db import models class Board(models.Model): title = models.CharField(max_length = 100) contents = models.TextField() created_at = models.DateTimeField(auto_now_add = True) updated_at = models.DateTimeField(auto_now = True) class Meta: db_table = 'boards' class Comment(models.Model): contents = models.CharField(max_length = 100) created_at = models.DateTimeField(auto_now_add = True) updated_at = models.DateTimeField(auto_now = True) board = models.ForeignKey('Board', on_delete = models.CASCADE, related_name = 'comments') class Meta: db_table = 'comments'
2. 시리얼라이저 생성
시리얼라이저란 Django REST framework을 사용하면서 추가되는 중요 기능 중 하나입니다.
퓨어 장고를 하면서 저희는 request 데이터를 변환해서 처리한 후 다시 json 으로 response 해주었습니다.
하지만, DRF에서는 serializers.py를 통한 직렬화로 쿼리 셋 및 모델 인스턴스와 같은 복잡한 데이터를 네이티브 Python 데이터 유형으로 변환한 다음 JSON, XML 또는 다른 콘텐츠 유형 으로 쉽게 렌더링 해줄 수 있습니다.
즉, client의 request를 직렬화를 통해 주고받고 할 수 있습니다.
- serializers.py 생성(기본 apps에 없습니다. 생성해야 합니다!)
from rest_framework import serializers
from .models import Board, Comment
class BoardSerializer(serializers.ModelSerializer):
class Meta:
model = Board
fields = '__all__'
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['contents', 'board']
read_only = ['contents']
# 아래의 function은 댓글을 추가할때 댓글내용과 게시글pk가 같이 표현되지 않게하기 위한 기능이다.
# 원하는 필드를 return 해주는데 딕셔너리 형태로 작성하되 instance가 꼭 들어가야한다.
def to_representation(self, instance):
return {
'contents': instance.contents,
}
# 게시글을 불러올때 연결되어있는 댓글을 불러오기 위해서는 model은 Board이지만 댓글을 따로 지정해줘 fields에 추가해준다.
class BoardDetailSerializers(serializers.ModelSerializer):
#댓글을 따로 지정해주고 여러개의 댓글이 가능하게 many = True를 넣어준다.
comments = CommentSerializers(many = True)
class Meta:
model = Board
fields = ['title','content','comments']
3. Views.py 작성
게시글과 댓글을 생성하고 삭제, 수정할 수 있는 function을 나누어 Views를 작성해줍니다.
- views.py
from .models import Board, Comment from .serializers import BoardSerializers, CommentSerializers, BoardDetailSerializers from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status # 게시글의 목록과 생성 @api_view(['POST','GET']) def board_list_create(request): # 게시글 목록 불러오기 if request.method == 'GET': boards = Board.objects.all() serializer = BoardSerializers(boards, many = True) # Many = True 해줘야 여러 객체들을 불러올 수 있습니다. return Response(serializer.data, status = status.HTTP_200_OK) # 게시글 생성하기 elif request.method == 'POST': serializer = BoardSerializers(data = request.data) if serializer.is_valid(): # 유효성 검사 True/False값으로 결과값을 지정해줄 수 있다. serializer.save() # 저장 return Response(serializer.data, status = status.HTTP_201_CREATED) return Response(status = status.HTTP_400_BAD_REQUEST) # 게시글불러오기와 수정, 삭제 @api_view(['GET','DELETE','PUT']) def board_detail_delete_update(request, pk): # 게시글 불러오기 if request.method == 'GET': # 사용자가 요청한 path Parameter에 넣은 게시글의 pk값 불러오는 게시글의 pk와 일치하는지 검증 board = Board.objects.get(pk = pk) if board == None: return Response(status = status.HTTP_404_NOT_FOUND) #하나의 게시글에 여러개의 댓글을 같이 가져와야하기에 따로 지정해준 시리얼라이저를 사용합니다. serializer = BoardDetailSerializers(board) return Response(serializer.data, status = status.HTTP_200_OK) # 게시글 삭제하기 elif request.method == 'DELETE': board = Board.objects.get(pk = pk) if board == None: return Response(status = status.HTTP_404_NOT_FOUND) board.delete() return Response(status = status.HTTP_200_OK) # 게시글 수정하기 elif reqeust.method == 'PUT': board = Board.objects.get(pk = pk) if board == None: return Response(status = status.HTTP_404_NOT_FOUND) # 수정하기위한 보드 데이터를 불러와 client 요청에 따른 data를 담아주기, 부분적인 수정을 위해 patial = True를 해주어야함 serializer = BoardSerializers(board, data = request.data, patial = True) if serializer.is_valid(): # 수정 또한 유효성 검사가 필요 serializer.save() return Response(serializer.date, status = status.HTTP_201_CREATED) return Response(status = status.HTTP_400_BAD_REQUEST) # 게시글에 댓글달기 @api_view(['POST']) def comment(request, pk): # 게시글 댓글추가 if request.method == 'POST': board = Board.objects.get(pk = pk) # 클라이언트가 요청하는 게시글 if board == None: return Response(status = status.HTTP_404_NOT_FOUND) # ForeignKey로 연결되있는 게시글의 아이디를 같이 요청해야지 client가 요청한 게시글에 댓글을 추가하기위한 로직 request.data['board'] = board.id serializer = CommentSerializers(data = request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status = status.HTTP_200_OK) return Response(status = status.HTTP_400_BAD_REQUEST) # 댓글 수정,삭제 @api_view(['PUT','DELETE']) #여기서 pk는 게시글의 pk, urls.py에서 필요로 하기에 view에서 사용은 안하지만 선언은 해준다. def comments_update_delete(request, pk, comment_pk): #게시글 댓글 삭제 if request.method == 'DELETE': #내가 수정하고자 요청한 댓글의 pk와 get으로 가져오는 pk comment = Comment.objects.get(pk = comment_pk) if comment == None: return Response(status = status.HTTP_404_NOT_FOUND) comment.delete() return Response(status = status.HTTP_200_OK) #게시글 댓글 수정 elif request.method == 'PUT': comment = Comment.objects.get(pk = comment_pk) if comment == None: return Response(status = status.HTTP_404_NOT_FOUND) #게시글 수정과 같은방법으로 진행해준다. serializer = CommentSerializers(comment, data = request.data, partial = True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status = status.HTTP_200_OK) return Response(status = status.HTTP_400_BAD_REQUEST)
4. URL 지정
작성한 뷰 파일을 실행시키기 위한 url을 지정해주기 위해 메인 프로젝트 urls.py에서 apps의 urls.py로 향할 수 있게 지정해줍니다.
이후에 apps내에 urls.py를 만들어서 각 views에 연결해줍니다.
- config/urls.py
#config/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('boards/', include('boards.urls')) ] - boards/urls.py
from django.urls import path from .views import board_detail_delete_update, board_list_create, comment, comments_update_delete app_name = 'boards' urlpatterns = [ path('', board_list_create), path('<int:pk>/', board_detail_delete_update), path('<int:pk>/comments/', comment), path('<int:pk>/comments/<int:comment_pk>', comments_update_delete) ]
5. 마이그레이션 및 서버 가동
위의 과정을 끝냈다면 시작하기에서 설명했던 것처럼 models.py에 지정했던 테이블을 데이터베이스에 저장시키기 위한 마이그레이션과 마이 그레이트를 진행합니다.
- makemigrations / migrate
python manage.py makemigrations python manage.py migrate - 서버 실행
python manage.py runserver
6. 기능 확인
파이썬 기본 지정 서버인 127.0.0.1:8000에서 우리가 지정해준 /boards를 타고 가면 아래의 사진과 같은 화면을 볼 수 있다.
아래의 사진에서 보이듯이 게시글 리스트를 보여주고 GET과 POST가 가능합니다.
(POST를 해줄 때는 json 형식인 {" " : " " }을 이용해야 제대로 전달이 된다.)

이어서 127.0.0.1:8000/boards/1로 가면 1번 게시글과 댓글이 나오며 DELETE와 PUT이 가능합니다.
댓글은 직접 해보시는 게 좋겠습니다 :)

@api_view()를 통한 function based views로 C.R.U.D를 해봤습니다.
보시다시피 반복되는 문장이 많지만 내가 원하는 대로 로직을 구성할 수 있기에 장점과 단점이 존재하는 것 같습니다.
다음 시간에는 class based views를 할 건데 오늘 한 것과 크게 다를 바가 없으니 Mixin을 같이 해볼까 합니다 (예정)
긴 글 읽어주셔서 감사합니다.

'코딩일지 > DRF' 카테고리의 다른 글
| [D.R.F] Generic CBV로 게시글 C.R.U.D API 구현하기 (0) | 2021.11.22 |
|---|---|
| [D.R.F]Mixin CBV로 게시글 C.R.U.D API 구현하기 (4) | 2021.11.15 |
| [D.R.F] Class based View로 게시글 C.R.U.D API 구현하기 (0) | 2021.11.12 |
| [D.R.F] Django REST framework 시작 및 초기세팅 (0) | 2021.11.10 |