TIL 30 | Westagram Posting & Comment
Westagram 프로젝트를 진행하며 Django 세팅을 완료하고 User Model과 회원가입, 로그인 기능까지 구현했었다. 인증과 인가는 아직 진행하지 않았지만, 가입한 회원의 게시물 등록과 댓글 기능을 구현해봤다. 구현에 앞서 Westagram Project는 Github으로 연동되어 있으므로 새로 Github Repository를 만들어 SignIn 기능까지 완료하고 시작했다.
Modify User APP
User Table에 Nickname 추가
기존 User Table은 name
, email
, password
, phone_number
, age
만 가지고 있었다. 그런데 게시물 등록 기능을 구현하다 생각해보니, 등록했을때 유저의 정보를 표출할 경우 email을 넣자니 너무 난잡하고 이름을 넣자니 중복될 수 있어 애매했다. 그래서 Unique하면서 특징을 그대로 살릴 수있는 nickname
field를 추가했다.
class User(models.Model):
.
.
.
nickname = models.CharField(max_length=45, default="", unique=True)
Nickname 중복사용 금지
추가로, UserView에서 email
이 존재할 경우 EMAIL_ALREADY_EXIST
라는 에러를 return했었는데 nickname
이 존재할 경우도 DATA_ALREADY_EXIST
에러를 return하도록 했다.
if User.objects.filter(email = data['email']).exists():
# return JsonResponse({"MESSAGE":"EMAIL_ALREADY_EXIST"}, status=400)
return JsonResponse({"MESSAGE":"DATA_ALREADY_EXIST"}, status=400)
if User.objects.filter(nickname = data['nickname']).exists():
return JsonResponse({"MESSAGE":"DATA_ALREADY_EXIST"}, status=400)
Migration Error
nickname
에 unique=True
옵션을 설정하고 Migration하니, IntegrityError가 발생했다.
에러를 해결하기 위해 우선 Migration 파일을 지우고 unique
속성을 없앤 후 migrate했다. 그리고 Query를 이용해 직접 User들의 nickname에 서로 다른 값을 부여한 후 unique=True
로 수정하고 migrate했다.
Post & Comment Model
우선 게시물의 데이터와 사용자의 데이터는 그 성질이 달라 데이터베이스에서 테이블을 따로 관리한다고 하기에 앱을 분리하기 위해 Posts
App을 추가하였다. App 이름을 Postings
로 해야 했는데 너무 늦게 알아차렸고, 이름을 일일히 변경하고 나니 이전 Migration Data와 충돌해서 일단 posts
로 진행하였다.
Post와 Comment의 Model을 구현하기에 앞서 Database 관계도를 만들기 위해 AQueryTrool을 이용했다. ERD는 다음과 같이 구성했다.
Post의 Comment의 User는 User Table과 ForeginKey로 연결되고, Comment의 Post는 Post Table과 ForeginKey로 연결된다.
DateTimeField과 TimeZone 설정
이전에 Model에 대해 포스팅한적이 있는데, DateTimeField의 argument중 auto_now_add
는 오로지 Field가 Create될때 현재시간으로 지정한다. 데이터를 수정하고 싶다면 default
argument를 사용하는 것이 좋은데, 생성 시간은 수정할 일이 없으므로 auto_now_add=True
를 사용했다.
또한 Django에서 기본 시간은 UTC이므로 Setting에서 TimeZone 설정을 바꿔주었다.
# westagram/settings.py
TIME_ZONE = 'Asia/Seoul'
USE_TZ = False
다른 App의 Table을 ForeignKey로 사용
posts
App에서 users
App의 User
Class를 ForeignKey를 사용할 경우 주석처리한 코드로 했더니 에러가 나타났다. 참조할 Table의 이름을 AppName.TableName
으로 지정하니 제대로 적용되었다.
# posts/models.py
# user = models.ForeignKey('User', on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='comments')
Post & Comment Model
여러 시행착오 끝에 필요한 data에 따라 Post와 Comment의 Model을 작성해봤다. Model을 토대로 View Logic을 구현해보자.
from django.db import models
class Post(models.Model):
user = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='posts')
creation_time = models.DateTimeField(auto_now_add=True)
image = models.URLField()
post = models.TextField()
class Meta:
db_table = 'posts'
class Comment(models.Model):
user = models.ForeignKey('users.User', on_delete=models.CASCADE, related_name='comments')
post = models.ForeignKey('Post', on_delete=models.CASCADE, related_name='comments')
creation_time = models.DateTimeField(auto_now_add=True)
comment = models.TextField()
class Meta:
db_table = 'comments'
Post View
PostView의 기능은 Post와 Get을 사용하여 게시물을 등록하고, 표출해주는 것이다. 각 기능을 구현하기 위한 조건들은 다음과 같이 설정하여 Model을 작성했다.
게시물 등록
- 게시물을 등록하기 위해 사용자, 생성 시간, 이미지 url이 필요하다.
- 게시물 생성 시간은 등록하는 현재 시간이어야 한다.
- 등록된 사용자가 아닐 경우
Invalid User
에러를 반환한다. - 필요한 정보가 누락되었을 경우 KeyError를 반환한다.
게시물 표출
- 등록된 모든 게시물을 나열해야 한다.
- 게시물을 나타낼 때에는 등록한 사람, 게시물, 게시된 내용, 게시된 시각이 포함되어야 한다.
작성한 PostView Class
class PostView(View):
def post(self, request):
try:
data = json.loads(request.body)
if not User.objects.filter(email = data['email']).exists():
return JsonResponse({"MESSAGE":"INVALID_USER"}, status=400)
Post.objects.create(
user = User.objects.get(email=data['email']),
image = data['image'],
post = data['post'],
)
return JsonResponse({"MESSAGE":"SUCCESS"}, status=201)
except KeyError:
return JsonResponse({"MESSAGE":"KEY_ERROR"}, status=400)
def get(self, request):
posts = Post.objects.all()
results = []
for post in posts:
results.append(
{
"user" : post.user.nickname,
"image" : post.image,
"post" : post.post,
"creation_time" : post.creation_time
}
)
return JsonResponse({'resutls':results}, status=200)
UserView와 크게 다르지 않게 Model Class를 만들 수 있었고, GET Method에서 return하는 user
는 email
이 아닌 nickname
으로 하였다.
httpie request
게시물 등록, 표출 기능 모두 잘 작동하는 걸 볼 수 있다.
# 게시물 등록 기능
http -v POST 127.0.0.1:8000/posts/post email="[email protected]" image="https://img.hani.co.kr/imgdb/resize/2019/0121/00501111_20190121.JPG" post="갱얼쥐입니다"
# 게시물 표출 기능
http-v GET 127.0.0.1:8000/posts/post
Comment View
CommentView의 기능은 등록된 게시물에 댓글을 등록하고, 등록된 댓글을 나열하는 것이다. 각 기능을 구현하기 위한 조건들은 다음과 같이 설정하여 Model을 작성했다.
댓글 등록
- 댓글을 등록하기 위해 댓글이 달리는 게시물, 사용자, 생성시간, 댓글 내용이 필요하다.
- 댓글을 생성한 시간은 현재 시간이어야 한다.
- 등록된 사용자가 없다면
Invalid User
, 등록된 게시물이 없다면No Post
Error를 반환한다. - 필요한 정보가 누락될 경우 KeyError를 반환한다.
댓글 나열
- 1번 게시물에 등록된 댓글만을 표출할 수 있도록 구현하라.
- 댓글을 나열할 경우 댓글을 등록한 사용자, 댓글 내용, 생성시간이 포함되어야 한다.
작성한 CommentView Class
class CommentView(View):
def post(self, request):
try:
data = json.loads(request.body)
if not User.objects.filter(email=data['email']).exists():
return JsonResponse({"MESSAGE":"INVALID_USER"}, status=400)
if not Post.objects.filter(id = data['post']).exists():
return JsonResponse({"MESSAGE":"NO_POST"}, status=400)
Comment.objects.create(
user = User.objects.get(email=data['email']),
post_id = data['post'],
comment = data['comment']
)
return JsonResponse({"MESSAGE":"SUCCESS"}, status=201)
except KeyError:
return JsonResponse({"MESSAGE":"KEY_ERROR"}, status=400)
def get(self, request):
comments = Comment.objects.filter(post_id=1)
results = []
for comment in comments:
results.append(
{
"user" : comment.user.nickname,
"comment" : comment.comment,
"creation_time" : comment.creation_time
}
)
return JsonResponse({'resutls':results}, status=200)
- httpie로 입력받는 게시물 정보(
data['post']
는 마땅히 사용할 field가 없어 게시물의 id로 하였다.(image나 creation_time으로 할순 없으므로) - 1번 게시물에 달린 댓글만 표출하기 위해
Comment.objects.filter(post_id=1)
을 사용하여result
리스트에 추가하였다. - 댓글을 단 사용자의 정보는
nickname
으로 하였다.
httpie request
댓글 작성, 나열 모두 잘 구현된 것을 확인할 수 있었다.
# 댓글 등록 기능
http -v POST 127.0.0.1:8000/posts/comment email="[email protected]" comment="장동건입니다" post=1
# 댓글 나열 기능
http -v GET 127.0.0.1:8000/posts/comment
🤔 Curious
게시물을 GET할 경우 모든 게시물을 가져왔다. 특정 사용자가 등록한 모든 게시물을 가져오거나, 특정 날짜 이후에 등록한 게시물을 가져오는 등 조건이 붙어 있을 경우 어떻게 해결할까? 단순 View에서 해결하는 것이 아니라 사용자가 httipe로 지정하는 경우는?
Comment의 경우에도 첫번째 게시글의 댓글만 나열했다. Get Method의 Url에
posts/1/comments
는 첫번째 게시물의 댓글들,posts/2/comments
는 두번째 게시물의 댓글들을 가져오는 것처럼url
을 이용해 특정 게시물의 댓글을 가져올 수 있을까? Get에 Body가 없는데 어떻게 가능할까?
Author And Source
이 문제에 관하여(TIL 30 | Westagram Posting & Comment), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hkja0111/TIL-30-Westagram-Posting-Comment저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)