<시작 상태>
- models.py
# posts/models.py
from django.db import models
from django.urls import reverse
from users.models import User, MaxValueValidator, MinValueValidator
class Category(models.Model):
name = models.CharField("카테고리명", max_length=20)
def __str__(self):
return str(self.name)
class Post(models.Model):
category = models.ForeignKey(Category, verbose_name="카테고리", on_delete=models.DO_NOTHING, related_name="category_posts")
title = models.CharField("제목", max_length=100)
content = models.TextField("내용")
image = models.ImageField("사진", blank=True, null=True, upload_to='%Y/%m/%d')
star = models.IntegerField("별점", validators=[MinValueValidator(1), MaxValueValidator(5)])
created_at = models.DateTimeField("생성시간", auto_now_add=True)
updated_at = models.DateTimeField("마지막 수정시간", auto_now=True)
like = models.ManyToManyField(User, verbose_name="좋아요", related_name="like_posts")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
def __str__(self):
return str(self.title)
- 팀원들이랑 같이 미리 작성한 Post 모델에 Category 모델을 추가했다
- Post 모델에 category 필드를 만들어 Category 모델과 외래키 관계로 설정했다
- urls.py
# posts/urls.py
from django.urls import path
from posts import views
urlpatterns = [
path('', views.PostView.as_view(), name='post_view'),
path('study/', views.StudyFeedView.as_view(), name='study_feed_view'),
path('study/followings/', views.StudyFollowView.as_view(),
name='study_follow_view'),
path('breaktime/', views.BreaktimeView.as_view(), name='breaktime_view'),
path('breaktime/followings/', views.BreaktimeFollowView.as_view(),
name='breaktime_follow_view'),
path('<int:post_id>/', views.PostDetailView.as_view(), name='post_detail_view'),
path('<int:post_id>/likes/', views.PostLikesView.as_view(),
name='post_likes_view'),
path('comments/', views.CommentsView.as_view(), name='comment_view'),
path('comments/<int:comment_id>/',
views.CommentsDetailView.as_view(), name='comments_detail_view'),
]
- url도 미리 다 설정했다
- 메인페이지를 조회해야 하니 첫 번째 url에 접속하면 실행되는 StudyFeedView를 쓸 예정이다
<구현하기>
- 일단 url을 study와 breaktime으로 나눌 필요가 없었다
- url에 변수를 지정하는 게 가능하기 때문
- 프론트에서 공부 게시판을 누르면 study를 받아서 함수를 실행하게끔? 하는 그런 것 같다
- urls.py 수정
# posts.urls.py
...
urlpatterns = [
...
path('<str:category_name>/',
views.CategoryView.as_view(), name='category_view'),
path('<str:category_name>/followings/', views.CategoryFollowView.as_view(),
name='category_follow_view'),
...
]
- 바꾸는 김에 팔로잉 게시글 url도 바꾸고 함수명도 바꿨다
- serializers.py
# posts/serializers.py
from rest_framework import serializers
from posts.models import Post
class PostListSerializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
user = serializers.SerializerMethodField()
def get_category(self, obj):
return obj.category.name
def get_user(self, obj):
return obj.user.username
class Meta:
model = Post
fields = "__all__"
- 시리얼라이저는 일단 필드 뭐뭐 나오면 좋을지 모르겠어서 전부 나오게 했다
- 그리고 user랑 category가 숫자로 떠서 문자로 나오게끔 시리얼라이저메소드필드를 이용해서 유저 아이디, 카테고리 이름으로 뜨게 했다
- views.py
- 고난이 시작되었다
# posts/views.py
from django.db.models.query_utils import Q
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from posts.models import Post
from posts.serializers import PostListSerializer
class CategoryView(APIView):
def get(self, request, category_name):
"""카테고리별 글 목록 조회"""
posts = Post.objects.filter(category=category_name)
serializer = PostListSerializer(posts, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
- 전에 했던 프로젝트를 참조해서 이렇게 코드를 짰다
- filter를 쓴 이유는 category별로 게시글이 여러 개 있기 때문이다
- 포스트맨에서 실행하면 아래와 같은 에러가 뜬다
File "C:\Users\l\Desktop\Projects\03_project\AI-5_A4_BackOffice_Backend\AI-5_A4_DUTO\posts\views.py", line 26, in get
posts = Post.objects.filter(category=category_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: Field 'id' expected a number but got 'rest'.
- 이게 뭔소린지 몰라가지고 3~4시간을 헤맸다....
- 플젝 기간에는 집중 코딩시간이 없어야 된다고 생각한다.....질문을 할 수가 없다.....동기들한테 물어보면 되긴 하지만 누구한테 물어봐야 할지도 모르겠고 각자 해야 할 일들로 바쁠 거 같아서 못 물어보겠다...
- 튜터님들이 돌아오시는 5시까지 구글링으로 해결을 못 했다... 딱 나와 같은 사례로 질문한 사람을 못 찾았다,,
- 여튼 숫자가 들어가야 한다고 해서 카테고리의 id값인 1 또는 2를 넣으니까 제대로 필터링이 되면서 글들이 출력된다
- 근데 나는 주소창에 숫자가 아니라 카테고리명이 들어갔으면 하는거지...
- 역시나 튜터님이 답을 주셨다
# posts/views.py
...
class CategoryView(APIView):
def get(self, request, category_name):
"""카테고리별 글 목록 조회"""
posts = Post.objects.filter(category__name=category_name)
...
- category=를 category__name=으로 수정하면 되는 문제였다......
- 원하는 url로 원하는 값들이 나오는 것을 확인할 수 있었다
<다듬기>
- 필요한 필드만 보여주기
- 출력되는 걸 보니까 필요한가? 싶은 필드가 있다 id랑 created_at은 필요없는 것 같다
- 시리얼라이저를 수정해야겠다
# posts/serializers.py
...
class PostListSerializer(serializers.ModelSerializer):
...
class Meta:
model = Post
fields = ("category", "user", "title", "content",
"image", "star", "like", "updated_at",)
- 좋아요 누른 사람 유저아이디로 보이게 하기
- 엄밀히 따지면 내 파트는 아니긴 한데 그냥...숫자로 보이는 게 거슬려서 바꾼다
# posts/serializers.py
...
class PostListSerializer(serializers.ModelSerializer):
...
like = serializers.StringRelatedField(many=True)
...
- StringRelatedField를 사용하면 숫자를 문자로 보이게 바꿀 수 있다
- like에 id값에서 username값으로 변경되었다
- id랑 created_at 필드도 빠진 것을 확인할 수 있다