#개발 준비
bariBari23/django-vote-17th: 파트장/데모데이 투표 (github.com)
https://documenter.getpostman.com/view/25425757/2s93z9d3Md
# accounts/models.py
class User(AbstractUser):
part_list = (
('프론트엔드', '프론트엔드'),
('백엔드', '백엔드')
)
team_list = (
('RePick', 'Repick'),
('바리바리', '바리바리'),
('Hooking', 'Hooking'),
('Dansupport', 'Dansupport'),
('TherapEase', 'TherapEase')
)
name = models.CharField(max_length=8)
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
part = models.CharField(max_length=8, choices=part_list, default='백엔드')
team = models.CharField(max_length=16, choices=team_list, default='바리바리')
team_vote = models.BooleanField(default=False)
part_vote = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['password', 'name', 'email', 'part', 'team']
def __str__(self):
return self.name
- 회원가입에 필요한 필드는 아이디, 비밀번호, 이메일, 파트, 이름, 팀입니다.
- 아이디, 이메일은 중복될 수 없습니다. 회원가입 과정 중에 중복 체크는 자유롭게 하셔도 됩니다.
- (중복체크 API를 따로 제작 혹은 회원가입 완료 시에 한 번에 체크)
- 파트는 (프론트엔드, 백엔드) 중 하나를 선택할 수 있게 해주시면 됩니다.
- 팀은 (RePick, 바리바리, Hooking, Dansupport, TherapEse) 중 하나를 선택할 수 있게 해주시면 됩니다.
위 요구사항을 바탕으로 AbstractUser를 상속받는 User model을 만들었다.
team_vote와 part_vote는 각 팀/파트 투표에 참여했는지 확인하기 위해 넣었다. 다만 파트장 투표는 여러 사람을 뽑을 수 있도록 기능을 수정해서 part_vote는 쓸모 없어진듯...
파트와 팀은 정해진 리스트에서 choice하도록 만들었고, default값을 설정해주어야 하길래 우리 팀/파트로 해주었다.
#accounts/views.py
#로그아웃 함수
class LogoutView(APIView):
def post(self, request):
response = Response({
"message": "로그아웃 성공"
}, status=status.HTTP_202_ACCEPTED)
response.delete_cookie('refresh')
response.delete_cookie('access')
return response
로그아웃은 cookie의 token을 삭제하는 식으로 구현해주었다. 아예 token을 blacklist처리해버리는 방법을 하려다, 간단하게 구현하였다.
내 database를 보다가 갑자기 만든 적 없는 blacklist에 여러 token이 올라와져 있는것을 보았다. blasklistedtoken에는 아무것도 없었는데...
로그인을 할때마다 새롭게 생성되었다. 찾아보니 token에 로그인할때마다 생성되는 refresh token이 들어가고 있었다.
#votes/models.py
class Team_Vote(models.Model):
team_list = (
('RePick', 'RePick'),
('바리바리', '바리바리'),
('Hooking', 'Hooking'),
('Dansupport', 'Dansupport'),
('TherapEase', 'TherapEase')
)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='team_user')
team = models.CharField(max_length=16, choices=team_list)
def __str__(self):
return f'{self.user.name} : {self.team}'
팀과 파트장 투표 모델은 투표한 user와 선택한 team/파트장의 정보를 넣었다.
다만 Part_Vote 모델도 team_list처럼 정해진 리스트 내에서 투표하도록, 오타 같은 일이 없게 만들었는데 시간 낭비였던 것 같다.
team_list작성이 제일 오래걸린 듯.
#votes/views.py
class TeamVoteView(APIView):
def get(self, request, format=None):
vote = Team_Vote.objects.all()
serializer = TeamVoteSerializer(vote, many=True)
vote_count = Team_Vote.objects.filter().values('team').annotate(total=Count('team')).order_by('-total')
return Response({'message': "투표 조회", 'vote_count':vote_count, 'data': serializer.data}, status=HTTP_200_OK)
def post(self, request, format=None):
user = self.request.user
serializer = TeamVoteSerializer(data=request.data)
if serializer.is_valid():
# if Team_Vote.objects.filter(user=user, team=serializer.validated_data['team']):
# user_update = get_object_or_404(User, name=user.name)
# user_update.team_vote = False
# user_update.save()
# delete_vote = Team_Vote.objects.get(user=user, team=serializer.validated_data['team'])
# delete_vote.delete()
# return Response({'message': '투표 취소', 'data': serializer.data, 'user':user_update.team_vote}, status=HTTP_201_CREATED)
# else:
# if user.team == serializer.validated_data['team']:
# return Response({'message': '내 팀은 투표 할 수 없습니다!', 'data': serializer.errors},
# status=HTTP_400_BAD_REQUEST)
# elif Team_Vote.objects.filter(user=user):
# return Response({'message': '투표는 한 번만!', 'data': serializer.errors},
# status=HTTP_400_BAD_REQUEST)
# else:
# user_update=get_object_or_404(User, name=user.name)
# user_update.team_vote=True
# user_update.save()
# serializer.save(user=self.request.user, team=serializer.validated_data['team'])
# return Response({'message': '투표 성공', 'data': serializer.data, 'user':user_update.team_vote}, status=HTTP_201_CREATED)
if user.team == serializer.validated_data['team']:
return Response({'message': '내 팀은 투표 할 수 없습니다!', 'data': serializer.errors},
status=HTTP_400_BAD_REQUEST)
elif Team_Vote.objects.filter(user=user):
return Response({'message': '투표는 한 번만!', 'data': serializer.errors},
status=HTTP_400_BAD_REQUEST)
else:
user_update=get_object_or_404(User, name=user.name)
user_update.team_vote=True
user_update.save()
serializer.save(user=self.request.user, team=serializer.validated_data['team'])
return Response({'message': '투표 성공', 'data': serializer.data, 'user':user_update.team_vote}, status=HTTP_201_CREATED)
return Response({'message': '투표 실패', 'data': serializer.errors}, status=HTTP_400_BAD_REQUEST)
- 후보는 득표 순으로 내림차순 정렬되어 보여집니다
- 투표 방법에 대해서는 제약이 없습니다. 한 아이디당 한 번만 투표하게 만드셔도 좋고, 투표 버튼 누르는 대로 득표수가 올라가도 상관없습니다.
- 로그인하지 않은 사용자는 투표 페이지에 접근할 수는 있되, 투표는 불가능합니다.
- 파트장 투표 : 본인의 파트에 해당하는 파트장 투표만 할 수 있습니다.
- 데모데이 투표 : 본인이 속한 팀을 제외하고 투표를 할 수 있습니다.
vote_count = Team_Vote.objects.filter().values('team').annotate(total=Count('team')).order_by('-total')
득표수를 return하기 위해 'tema'값을 기준으로 득표수를 세고 vote_count리스트에 담았다.
order_by()함수를 이용해 득표수 변수인 total을 기준으로 내림차순으로 정렬하였다.
투표 기능에서 처음에는 투표 취소기능이 있는 것으로 만들었다.
그래서 팀 투표 데이터에 user정보와 team투표 정보가 같은 것이 있을 때를 가정했는데...기능이 없어져서 그대로 없어졌다. 아쉬워서 주석처리만 했다.🥲
그리고 같은 팀 투표와 여러번 투표는 안되도록 만들었다.
class PartVoteView(APIView):
def get(self, request, format=None):
vote = Part_Vote.objects.all()
serializer = PartVoteSerializer(vote, many=True)
vote_count = Part_Vote.objects.filter().values('part').annotate(total=Count('part')).order_by('-total')
return Response({'message': "투표 조회", 'vote_count':vote_count, 'data': serializer.data}, status=HTTP_200_OK)
def post(self, request, format=None):
user = self.request.user
serializer=PartVoteSerializer(data=request.data)
if serializer.is_valid():
if Part_Vote.objects.filter(user=user, part=serializer.validated_data['part']):
user_update = get_object_or_404(User, name=user.name)
user_update.part_vote = False
user_update.save()
delete_vote = Part_Vote.objects.get(user=user, part=serializer.validated_data['part'])
delete_vote.delete()
return Response({'message': '투표 취소', 'data': serializer.data,'user': user_update.part_vote}, status=HTTP_201_CREATED)
else:
user_update = get_object_or_404(User, name=user.name)
user_update.part_vote = True
user_update.save()
serializer.save(user=self.request.user, part=serializer.validated_data['part'])
return Response({'message':'투표 성공', 'data': serializer.data,'user': user_update.part_vote}, status=HTTP_201_CREATED)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
파트장 투표는 여러명 투표가 가능하도록 만들었다.
마찬가지로 get method를 통해 vote_count에는 유저와 유저당 득표수, data에는 투표한 사람과 투표받은 사람을 담아서 return한다. 이거 만들 때 익명으로 할지 확실하게 정해지지 않아서 그냥 모두 보냈다.
api문서 작성 후 AWS로 배포했다.
오류
1. https를 설정하고 나면 http~~로 연결하면 안된다.
http~~는 보안상 get만 가능하다. api문서를 로컬 주소로 만들다보니까 프론트랑 오류가 있었다..
2. 배포시 migrations 파일 오류
배포하기 전에 model수정을 굉장히 많이 했는데, docker에서 migrations파일과 중간에 충돌이 난 듯했다.
제대로 데이터베이스가 만들어지지 않았는데, migrations파일을 삭제하고 다시 만들어주었더니 문제가 해결됐다.
3. 변수 이름
생각보다 오타나 소통 오류로 인한 변수 오류가 있었다...
문서를 꼼꼼하게 작성하자.
'django > 정리' 카테고리의 다른 글
[Django] 비동기식 데이터 전달/불러오기 - Redis&Celery (1) (0) | 2024.07.19 |
---|---|
[Django] UML Diagram 자동생성 (0) | 2024.04.05 |
AWS 배포(4) - SSH 연결 및 docker 관리 (1) | 2023.05.24 |
AWS 배포(3) - https, 도메인 (0) | 2023.05.24 |
AWS 배포(2) - EC2, RDS, github action (0) | 2023.05.24 |