학습주제
투표(Votes) 기능 구현하기
학습내용
지난시간 Choice의 Foreignkey를 이용해서 vote의 숫자를 계산하는 메소드를 이용한 votes_count 필드를 작성하였다.
이번엔 직접 Vote를 만들 수 있는 시리얼라이저와 뷰를 구현해 보려고 한다.
시리얼라이저에서
class VoteSerializer(serializers.ModelSerializer):
voter = serializers.ReadOnlyField(source='voter.username')
class Meta:
model = Vote
fields = ['id', 'question', 'choice', 'voter']
voter는 읽기 전용으로 생성해준다. (수정불가)
필즈도 정의해준다.
뷰로 이동
vote를 만들 수 있는 뷰를 만드는데 List형과 Detail 둘다 만든다. 수정도 해야하기 때문에 Detail도 필요함.
class VoteList는 QuestionList와 유사하다.
IsAuthenticated는 로그인을 안했을 경우, 조회기능도 제공하지 않음
vote같은 경우는 아무 vote나 보여주어선 안됨. 내가 한 vote만 보여주어야 함. 이런 조건을 적용할 List를 보여줄 queryset를 정의해주어야 한다. 이는 def get_queryset
를 이용한다
class GenericAPIView(views.APIView):
에 있는 get_queryset
을 오버라이딩 한 것.
class VoteList(generics.ListCreateAPIView):
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self, *args, **kwargs):
return Vote.objects.filter(voter=self.request.uesr)
class VoteDetail은 QuestioDetail과 유사,
모든 vote를 불러오는데
Update와 Delete는 내가 한 투표에 대해서만 접근 가능해야한다.
permissions.IsAuthenticated 외에 그러한 기능을 하는 클래스를 추가한다
QuestionDetail때는 permissions.py를 구현하여, 해당 유저만 업데이트, 삭제를 할 수 있게 했었다.
permissions.py로 이동해 비슷한걸 만들어준다.
class IsVoter(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.voter == request.user
class VoteDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Vote.objects.all()
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated, IsVoter]
이렇게 로그인, 작성자만 접근할 수 있게 되었다.
또한 VoteList에서 생성을 담당하기 때문에, 여기서 투표를 했을 경우, 그 Vote내부의 voter에 현재 접속한 사용자가 넘어가도록 한다.
url을 연결한다
path('vote/', VoteList.as_view()),
path('vote/<int:pk>/', VoteDetail.as_view()),
처음에 오류났었음. uesr을 user로 정정.
Vote List에서 하단에 질문과 답안을 선택할 수있다. 아직 보니까 choice는 어떤 것이든 다 선택할 수 있게 되어 있었다.
생성된 후, 다시 돌아가보니 정상적으로 반영되어 있다.
만일 question에 연결되지 않은 choice를 선택하면 이런 에러가 난다.