투표(Votes) 기능 구현하기 1 - Models

data_hamster·2023년 4월 30일
0

학습주제
로그인 한 사용자의 투표

학습내용
아직 polls_api에 투표하는 기능을 만들지 않았음. 투표는 장고 기반 polls앱에서 구현했었음.

votes라는 숫자를 1 증가시키는 것만 기능하기에 누구든지 vote를 여러번 누를 수 있게됨.

models.py 에서
vote모델을 별도로 만듦.
새로운 기능을 구현해본다
하나의 question에 대해 Voter는 하나의 투표만 할 수 있음. 제약을 걸어준다.

class Vote(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
    voter = models.ForeignKey(User, on_delete=models.CASCADE)    

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['question', 'votesr'], name='unique_votesr_for_questions')
        ]

question과 voter에 하나의 레코드만 생성된다.
모델을 수정했으니 migration을 해준다
(주의: 만일 잘못된 필드이름으로 migrations을 해주면 해당 migrations을 지우고 다시 migrations을 해줘야 함. 그 위에 마이그레이션을 하면 잘못된 이름으로 진행됨)

장고 셀에서 vote를 불러와본다
그 전에 question, choice, user를 1개 씩 생성한다.

from polls.models import *
question = Question.objects.first()
choice = question.choices.first()
from django.contrib.auth.models import User
user = User.objects.get(username='wook')

Vote.objects.create(voter=user, question=question, choice=choice)
Vote.objects.first()

question.id
1


아직 question의 바다가 투표되지 않았다. 그 이유는 Choice 모델에 votes가 숫자 필드이기 때문
그래서 우리는 Serializer를 변경해서 ChoiceSerializer에서 votes를 필드로 갖는게 아닌 Vote 테이블에서 몇개나 투표받았는지 값을 카운트해서 값을 표시해주도록 바꾼다.

votes_count = serializers.SerializerMethodField()

    def get_votes_count(self, obj):
        return obj.vote_set.count()

위 코드에서 get_votes_count 메서드에서는 obj.vote_set.count()와 같이 Choice 객체(obj)의 vote_set 속성을 사용하여 해당 선택지에 대한 모든 Vote 객체를 가져온 후, count 메서드를 사용하여 해당 객체의 개수를 계산합니다. 이렇게 계산된 값을 votes_count 필드의 값으로 반환하여, 해당 선택지에 대한 전체 투표 수를 계산합니다.

여기서 obj는 choice. Vote와 foreignkey로 연결되어 있으므로, 한 개의 choice에 여러개의 vote가 존재한다. 예를들어 Question : Choice : voter 순이면, 휴가 : 바다 :wook, 휴가 : 바다 : user1, 휴가 : 바다 : user2.
이런식의 조합인 Vote가 생성됨. 그럼 Choice 입장에서 vote들의 집합은 vote_set으로(related_name이 정해지지 않았기에) 접근할 수 있고, 우리가 원하는 해당 choice의 투표 수는 obj.vote_set.count()가 되는 것이다. 기존에 votes를 IntegerField로 만든 것과 다른 접근 방식이다.
vote는 질문, 선택지, 유저를 레코드로 하는 테이블이고, 추후 해당 선택지에 어떤 유저들이 투표했는지도 알 수 있게 된다.

일단 chatgpt에선 시리얼라이저에 메소드필드를 갖는 필드가 있게되면, 그 메소드는 명시적으로 작성해주면 인식한다고한다. 예 get_votes_count 여러개도 가능하나 복잡해질 가능성이 있다.

profile
반갑습니다 햄스터 좋아합니다

0개의 댓글