<동행 구하기>
- 등록
- 오랜만에 CRUD 했더니 에러가 계속 난다...
# accompanies/models.py
from django.db import models
from users.models import User
from exhibitions.models import Exhibition
class Accompany(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="get_accompanies",
verbose_name="동행구하기 작성자",
)
exhibition = models.ForeignKey(
Exhibition,
on_delete=models.CASCADE,
related_name="accompanies",
verbose_name="전시회 정보",
)
content = models.TextField("동행구하기 내용")
personnel = models.PositiveIntegerField("동행인원")
start_time = models.DateTimeField("모임시작시간")
end_time = models.DateTimeField("모임종료시간")
created_at = models.DateTimeField("생성시간", auto_now_add=True)
updated_at = models.DateTimeField("수정시간", auto_now=True)
def __str__(self):
return str(self.content)
- 처음에 여러 전시회에 여러 동행 댓글이 있을 수 있으니까 ManyToMany라 생각해서 그렇게 했는데 자꾸 오류가 났다
- 이전 프로젝트를 보니 외래키로 되어 있길래 그렇게 수정했다
- 그랬는데도 계속 에러가 났다..
- 문제는 매니투매니일 때 데이터베이스에 이미 반영이 돼서 수정이 안 되는 거였다
- 데이터베이스를 날리고 다시 makemigrations, migrate 하니 게시글이 제대로 작동된다..ㅠㅠ
# accompanies/urls.py
from django.urls import path
from accompanies import views
urlpatterns = [
path("<int:exhibition_id>/", views.AccompanyView.as_view(), name="accompany_view"),
]
# accompanies/views.py
from rest_framework import status
from rest_framework.generics import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from accompanies.serializers import AccompanyCreateSerializer
class AccompanyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def post(self, request, exhibition_id):
"""동행구하기 댓글 작성하기\n
Args:
request.data["content"] (char): 동행구하기 내용\n
request.data["personnel"] (int): 동행 목표 인원\n
request.data["start_time"] (datetime): 모임 시작 시간\n
request.data["end_time"] (datetime): 모임 종료 시간\n
exhibition_id (int): 해당 댓글이 등록될 전시회 게시글의 pk값\n
Returns:
HTTP_201_CREATED : 댓글 등록 완료\n
HTTP_400_BAD_REQUEST : 값이 제대로 입력되지 않음\n
HTTP_401_UNAUTHORIZED : 로그인 하지 않은 사용자
"""
serializer = AccompanyCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, exhibition_id=exhibition_id)
return Response(
{"message": "동행 구하기 글이 등록되었습니다.", "data": serializer.data},
status=status.HTTP_201_CREATED,
)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# accompanies/serializers.py
from rest_framework import serializers
from accompanies.models import Accompany
class AccompanyCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Accompany
fields = ("content", "personnel", "start_time", "end_time")
- 조회
- 조회 기능은 무난하게 포스트맨 테스트를 통과했다
- models.py와 urls.py는 동일하다
# accompanies/views.py
...
from accompanies.serializers import AccompanySerializer
from exhibitions.models import Exhibition
class AccompanyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def get(self, request, exhibition_id):
"""동행구하기 댓글 전체 조회하기\n
Args:
exhibition_id (int): 해당 댓글이 조회될 전시회 게시글의 pk값\n
Returns:
HTTP_200_OK : 댓글 조회 완료\n
HTTP_404_NOT_FOUND : 해당하는 전시회 게시글을 찾을 수 없음\n
"""
exhibition = get_object_or_404(Exhibition, id=exhibition_id)
accompanies = exhibition.accompanies.all()
serializer = AccompanySerializer(accompanies, many=True)
return Response(
{"message": "조회를 성공하셨습니다.", "data": serializer.data},
status=status.HTTP_200_OK,
)
# accompanies/serializers.py
...
class AccompanySerializer(serializers.ModelSerializer):
class Meta:
model = Accompany
fields = "__all__"
- 수정
# accompanies/urls.py
...
urlpatterns = [
...
path(
"detail/<int:accompany_id>/",
views.AccompanyView.as_view(),
name="accompany_view",
),
]
# accompanies/views.py
...
from accompanies.models import Accompany
...
class AccompanyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def get(self, request, exhibition_id):
...
def post(self, request, exhibition_id):
...
def put(self, request, accompany_id):
"""동행 구하기 댓글 수정하기\n
Args:
request.data["content"] (char): 동행 구하기 내용\n
request.data["personnel"] (int): 동행 목표 인원\n
request.data["start_time"] (datetime): 모임 시작 시간\n
request.data["end_time"] (datetime): 모임 종료 시간\n
accompany_id (int): 해당 동행구하기 댓글의 pk값\n
Returns:
HTTP_200_OK : 댓글 수정 완료\n
HTTP_400_BAD_REQUEST : 값이 제대로 입력되지 않음\n
HTTP_403_FORBIDDEN : 권한이 없는 사용자
"""
accompany = get_object_or_404(Accompany, id=accompany_id)
if request.user == accompany.user:
serializer = AccompanyCreateSerializer(accompany, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(
{"message": "동행 구하기 글이 수정되었습니다.", "data": serializer.data},
status=status.HTTP_200_OK,
)
else:
return Response(
{"message": "요청이 올바르지 않습니다.", "errors": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
else:
return Response(
{"message": "권한이 없습니다.", "errors": serializer.errors},
status=status.HTTP_403_FORBIDDEN,
)
- 삭제
# accompanies/views.py
...
class AccompanyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def get(self, request, exhibition_id):
...
def post(self, request, exhibition_id):
...
def put(self, request, accompany_id):
...
def delete(self, request, accompany_id):
"""동행 구하기 댓글 삭제하기\n
Args:
accompany_id (int): 해당 동행 구하기 댓글의 pk값\n
Returns:
HTTP_204_NO_CONTENT : 댓글 삭제 완료\n
HTTP_403_FORBIDDEN : 권한이 없는 사용자
"""
accompany = get_object_or_404(Accompany, id=accompany_id)
if request.user == accompany.user:
accompany.delete()
return Response(
{"message": "동행 구하기 글이 삭제되었습니다."}, status=status.HTTP_204_NO_CONTENT
)
else:
return Response({"message": "권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
<동행 신청하기>
- 등록
# accompanies/urls.py
...
urlpatterns = [
...
path("<int:accompany_id>/apply/", views.ApplyView.as_view(), name="apply_view"),
]
# accompanies/views.py
...
from accompanies.serializers import ApplyCreateSerializer
class ApplyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def post(self, request, accompany_id):
"""동행 신청하기 댓글 작성하기\n
Args:
request.data["content"] (char): 동행 신청하기 내용\n
accompany_id (int): 해당 댓글이 등록될 동행 구하기 댓글의 pk값\n
Returns:
HTTP_201_CREATED : 댓글 등록 완료\n
HTTP_400_BAD_REQUEST : 값이 제대로 입력되지 않음\n
HTTP_401_UNAUTHORIZED : 로그인 하지 않은 사용자
"""
serializer = ApplyCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, accompany_id=accompany_id)
return Response(
{"message": "동행 신청하기 댓글이 등록되었습니다.", "data": serializer.data},
status=status.HTTP_201_CREATED,
)
else:
return Response(
{"message": "요청이 올바르지 않습니다.", "errors": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
# accompanies/serializers.py
...
from accompanies.models import Apply
class ApplyCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Apply
fields = ("content",)
- 수정
# accompanies/urls.py
...
urlpatterns = [
...
path("apply/<int:apply_id>/", views.ApplyView.as_view(), name="apply_view"),
]
# accompanies/views.py
...
from accompanies.models import Apply
...
class ApplyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def post(self, request, accompany_id):
...
def put(self, request, apply_id):
"""동행 신청하기 댓글 수정하기\n
Args:
request.data["content"] (char): 동행 구하기 내용\n
apply_id (int): 해당 동행 신청하기 댓글의 pk값\n
Returns:
HTTP_200_OK : 댓글 수정 완료\n
HTTP_400_BAD_REQUEST : 값이 제대로 입력되지 않음\n
HTTP_401_UNAUTHORIZED : 로그인 하지 않은 사용자\n
HTTP_403_FORBIDDEN : 권한이 없는 사용자
"""
apply = get_object_or_404(Apply, id=apply_id)
if request.user == apply.user:
serializer = ApplyCreateSerializer(apply, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(
{"message": "동행 신청하기 댓글이 수정되었습니다.", "data": serializer.data},
status=status.HTTP_200_OK,
)
else:
return Response(
{"message": "요청이 올바르지 않습니다.", "errors": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
else:
return Response(
{"message": "권한이 없습니다.", "errors": serializer.errors},
status=status.HTTP_403_FORBIDDEN,
)
- 삭제
# accompanies/views.py
...
class ApplyView(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def post(self, request, accompany_id):
...
def put(self, request, apply_id):
...
def delete(self, request, apply_id):
"""동행 신청하기 댓글 삭제하기\n
Args:
apply_id (int): 해당 동행 신청하기 댓글의 pk값\n
Returns:
HTTP_204_NO_CONTENT : 댓글 삭제 완료\n
HTTP_401_UNAUTHORIZED : 로그인 하지 않은 사용자\n
HTTP_403_FORBIDDEN : 권한이 없는 사용자
"""
apply = get_object_or_404(Apply, id=apply_id)
if request.user == apply.user:
apply.delete()
return Response(
{"message": "동행 신청하기 댓글이 삭제되었습니다."}, status=status.HTTP_204_NO_CONTENT
)
else:
return Response({"message": "권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
<추가 수정사항>
- 동행 구하기 댓글 조회 시 그 아래 달린 동행 신청하기 댓글이 같이 나오게끔 수정
# accompanies/serializers.py
from rest_framework import serializers
from accompanies.models import Accompany, Apply
...
class ApplySerializer(serializers.ModelSerializer):
class Meta:
model = Apply
fields = "__all__"
...
class AccompanySerializer(serializers.ModelSerializer):
applies = ApplySerializer(many=True)
class Meta:
model = Accompany
fields = "__all__"
- AccompanySerializer에 applies 필드를 추가해준다
- Apply 모델에 accompany 필드가 Accompany 모델을 참조하는 외래키로 되어 있는데 이 필드의 related_name으로 필드명을 지정해준다(역참조 하는 거라 생각하면 될 듯)
- 다른 이름으로 맘대로 정하면 아래와 같은 에러가 난다
AttributeError: Got AttributeError when attempting to get a value for field `apply` on serializer `AccompanySerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Accompany` instance.
Original exception text was: 'Accompany' object has no attribute 'apply'.
- 그리고 applies는 ApplySerializer에서 받아오기 때문에 ApplySerializer가 AccompanySerializer보다 먼저 선언되어 있어야 함!! 위치 중요!!!