Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- RESTfulAPI
- promise
- 해시충돌
- 리스트컴프리헨션
- 인증인가
- QuerySet
- 알고리즘
- docker
- clone-coding
- decorator
- django
- DP
- wecode
- Python
- 파이썬입출력
- **kwargs
- 파이썬리스트컴프리헨션
- CSS
- 인터넷 네트워크
- clone coding
- 자바스크립트
- JavaScript
- 파이썬문법
- 코딩테스트파이썬
- 자료구조
- 파이썬
- bcrypt
- 윈도우우분투듀얼부팅
- 백준
- *args
Archives
- Today
- Total
개발기록장
[Django] 인스타그램 클론 코딩(4) - 게시물과 댓글 C.R.U.D (RESTful API) 본문
[이전 글]
[Django] 인스타그램 클론 코딩(3) - Authorization Decorator 만들고 활용하기
[다음 글]
[Django] 인스타그램 클론 코딩(5) - 좋아요(Like) 기능 구현
1. 구현해야 할 기능
- 게시물(post)과 관련된 기능을 처리할 app생성 (post라는 이름으로 생성함)
- 게시물 및 댓글 기능구현을 위한 model 생성
- RESTful하게 게시글 및 댓글 CRUD 구현
2. post/models.py
from django.db import models
from user.models import User
# 게시물 관련 테이블
class Post(models.Model):
user = models.ForeignKey('user.User', on_delete=models.CASCADE)
image_url = models.URLField(max_length=500)
content = models.TextField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'posts'
# 댓글 관련 테이블
class Comment(models.Model):
user = models.ForeignKey('user.User', on_delete=models.CASCADE)
post = models.ForeignKey('Post', on_delete=models.CASCADE)
content = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'comments'
- Post 클래스는 게시물에 대한 모델로 작성자를 의미하는 user, 이미지의 url 주소가 들어갈 image_url, 게시물의 내용이 들어갈 content로 구성하였다.
- Comment 클래스는 댓글에 관련 모델로, Post와 마찬가지로 댓글 작성자를 의미하는 user, 어느 게시물에 달린 댓글인지를 나타내는 post, 그리고 댓글 내용이 들어갈 content로 구성하였다.
- 하나의 게시물에는 여러개의 댓글이 달릴 수 있으므로 1:N 관계가 성립한다. Comment의 post필드에 ForeignKey 옵션으로 1:N 관계를 구현하였다.
- 한 명의 유저가 여러 게시물 또는 여러 댓글을 작성할 수 있으므로 User와 Post, User와 Comment 모두 1:N 관계를 성립하며, 이를 모두 ForeignKey 옵션으로 구현하였다.
3-1. post/views.py (게시물 관련 CRUD)
import json
from json.decoder import JSONDecodeError
from django.views import View
from django.http import JsonResponse
from .models import Post, Comment
from user.models import User
from user.utils import login_decorator
class PostView(View):
@login_decorator
def post(self, request):
data = json.loads(request.body)
user = request.user
image_url = data.get('image_url', None)
content = data.get('content', None)
# KEY_ERROR check
if not image_url:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
post = Post.objects.create(
user = user,
image_url = image_url,
content = content
)
return JsonResponse({'message': 'SUCCESS'}, status=200)
def get(self, request):
post_list = [{
'user' : post.user.name,
'image_url' : post.image_url,
'content' : post.content,
'created_at': post.created_at,
'updated_at': post.updated_at,
} for post in Post.objects.all()
]
return JsonResponse({'data': post_list}, status=200)
class PostDetailView(View):
def get(self, request, post_id):
# valid post check
if not Post.objects.filter(id=post_id).exists():
return JsonResponse({'message': 'INVALID_POST'}, status=404)
context = {}
# post 정보
post = Post.objects.get(id=post_id)
context['user'] = post.user.name
context['image_url'] = post.image_url
context['content'] = post.content
context['created_at'] = post.created_at
# comment 정보
comments = Comment.objects.filter(post=post)
if comments:
comment_list = [{
'user' : comment.user.name,
'content' : comment.content,
'created_at': comment.created_at
} for comment in comments
]
context['comment_list'] = comment_list
return JsonResponse({'data': context}, status=200)
# update
@login_decorator
def post(self, request, post_id):
try:
data = json.loads(request.body)
# valid post check
if not Post.objects.filter(id=post_id).exists():
return JsonResponse({'message': 'INVALID_POST'}, status=404)
post = Post.objects.get(id=post_id)
# valid user check
if post.user != request.user:
return JsonResponse({'message': 'INVALID_USER'}, status=400)
post.image_url = data.get('image_url', post.image_url)
post.content = data.get('content', post.content)
post.save()
return JsonResponse({'message': 'SUCCESS'}, status=200)
except JSONDecodeError:
return JsonResponse({'message': 'REQUEST_BOBY_DOES_NOT_EXISTS'}, status=400)
@login_decorator
def delete(self, request, post_id):
# valid post check
if not Post.objects.filter(id=post_id).exists():
return JsonResponse({'message': 'INVALID_POST'}, status=400)
post = Post.objects.get(id=post_id)
# valid user check
if post.user != request.user:
return JsonResponse({'message': 'INVALID_USER'}, status=401)
post.delete()
return JsonResponse({'message': 'SUCCESS'}, status=200)
- PostView
- post 메소드 : 게시물 작성(Create) 기능 담당. 로그인이 필수인 기능이기 때문에 login_decorator로 유저의 권한을 검증
- get 메소드 : 인스타그램에 들어가면 로그인하지 않아도 볼 수 있는 전체 게시물 데이터를 가져오는 기능을 담당
- PostDetailView - post_id를 url에서 받아서 처리할 수 있는 기능을 모아 둔 view.
- get 메소드 : url에서 받은 post_id와 일치하는 하나의 게시물에 대한 세부 데이터를 보여주는(Read) 기능을 담당. 댓글(comment)이 있다면 comment까지 보여준다.
- post 메소드 : url에서 받은 post_id와 일치하는 하나의 게시물을 수정(Update)하는 기능을 담당. 로그인이 필수일 뿐만 아니라 게시물을 작성한 유저만 수정이 가능해야 하기 때문에 post.user와 request.user가 일치하는지 체크하는 로직이 필요하다.
- delete 메소드 : url에서 받은 post_id와 일치하는 하나의 게시물을 삭제(Delete)하는 기능을 담당. Update와 마찬가지로 게시물을 작성한 유저만 삭제가 가능해야 하기 때문에 이를 체크하는 로직이 필요하다.
3-2. post/views.py (댓글 관련 CRUD)
class CommentView(View):
@login_decorator
def post(self, request):
data = json.loads(request.body)
user = request.user
post_id = data.get('post', None)
content = data.get('content', None)
# KEY_ERROR check
if not (post_id and content):
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
# valid post check
if not Post.objects.filter(id=post_id).exists():
return JsonResponse({'message': 'INVALID_POST'}, status=400)
Comment.objects.create(
user = user,
post = Post.objects.get(id=post_id),
content = content
)
return JsonResponse({'message': 'SUCCESS'}, status=200)
class CommentDetailView(View):
# update
@login_decorator
def post(self, request, comment_id):
try:
data = json.loads(request.body)
content = data.get('content', None)
# KEY_ERROR check
if not content:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
comment = Comment.objects.get(id=comment_id)
# valid user check
if comment.user != request.user:
return JsonResponse({'message': 'INVALID_USER'}, status=401)
comment.content = content
comment.save()
return JsonResponse({'message': 'SUCCESS'}, status=200)
except JSONDecodeError:
return JsonResponse({'message': 'REQUEST_BOBY_DOES_NOT_EXISTS'}, status=400)
@login_decorator
def delete(self, request, comment_id):
# vaild comment check
if not Comment.objects.filter(id=comment_id).exists():
return JsonResponse({'message': 'INVALID_COMMENT'}, status=400)
comment = Comment.objects.get(id=comment_id)
# valid user check
if comment.user != request.user:
return JsonResponse({'message': 'INVALID_USER'}, status=401)
comment.delete()
return JsonResponse({'message': 'SUCCESS'}, status=200)
- CommentView
- post 메소드 : 댓글을 작성(Create)하는 기능을 담당. 게시물과 마찬가지로 로그인이 필수인 서비스이기 때문에 login_decorator로 유저의 권한을 검증해야 한다.
- CommentDetailView
- post 메소드 : url에서 받은 comment_id와 일치하는 id의 댓글을 수정(Update)하는 기능. 게시물과 마찬가지로 댓글을 작성한 사람만 수정이 가능해야 하므로 comment.user와 request.user가 일치하는지 확인해야 한다.
- delete 메소드 : url에서 받은 comment_id와 일치하는 id의 댓글을 삭제(Delete)하는 기능. Update와 마찬가지로 댓글을 작성한 사람만 삭제가 가능해야 하므로 이를 체크하는 로직을 구현하였다.
4. post/urls.py
각 View에 엔드포인트 추가
from django.urls import path
from .views import (
PostView,
PostDetailView,
CommentView,
CommentDetailView,
)
urlpatterns = [
path('', PostView.as_view()),
path('/<int:post_id>', PostDetailView.as_view()),
path('/comment', CommentView.as_view()),
path('/comment/<int:comment_id>', CommentDetailView.as_view()),
]
- 참고
RESTful API에 Update에는 PUT / PATCH / POST 무슨 메소드를 써야 할까?
1) put : 전체를 업데이트할 때 주로 사용
2) patch : 부분을 업데이트할 때 주로 사용
3) post : RESTful API 이전에는 POST로 모든 update를 처리하다. RESTful API로 넘어오면도 아직 POST로 update를 처리하는 경우가 많다.
그런데 3번의 경우처럼 POST로 create와 update를 모두 구현하면 구분을 위해 억지로 다른 class에 나눠야 하는지에 대한 의문이 있었는데,
일단 create와 update는 url이 다르기 때문에(update의 경우 url에서 특정 id를 받아야 하므로) class를 나누어 써야 한다.
(한 class에 쓴다고 하더라도 에러가 나는 것은 아니지만 권장되지는 않는다)
'TIL > Django' 카테고리의 다른 글
[Django] 인스타그램 클론 코딩(6) - 팔로우(follow) 기능 구현 (0) | 2021.02.10 |
---|---|
[Django] 인스타그램 클론 코딩(5) - 좋아요(Like) 기능 구현 (0) | 2021.02.09 |
[Django] 인스타그램 클론 코딩(3) - Authorization Decorator 만들고 활용하기 (1) | 2021.02.08 |
[Django] 인스타그램 클론 코딩(2) - 로그인 기능 구현 (0) | 2021.02.02 |
[Django] 인스타그램 클론 코딩(1) - 회원가입 기능 구현 (0) | 2021.02.02 |