A ship in harbor is safe, but that is not what ships are built for.

개발일지/AI 캠프

내일배움캠프 AI - 77일차 TIL, 2022.12.19

플리피나리 2022. 12. 20. 20:28
반응형

스파르타 코딩클럽 내일배움캠프 AI 웹개발자양성과정 3회차

2022.12.19. 77일차 - TIL

 

 

1. 모집게시글 상태 변화

우리 프로젝트의 주제가 축제에 동행할 인원을 모집하는 것인데 아직 모집상태를 마감으로 변경하는 어떠한 동작도 존재하지 않는다. 그래서 각자 추가할 기능을 개발하고자 할 때 나는 수락한 신청 내역을 카운트해 모집게시글의 상태를 마감으로 변경하는 기능을 만들기로 했다.

 

혼자서 끄적여본 동작 방법...

일단 개발을 위한 사고회로는 다음과 같았다.

1) 모집마감인 게시글은 버튼을 활성화시키지 않는다.

2) 신청을 수락으로 누른 순간 현재 인원을 1증가시킨다. 이 현재 인원과 모집정원을 비교해 모집상태를 진행중, 마감으로 설정한다.

3) 그러면 해당 모델에 현재 인원을 저장할 integerfield가 필요하겠네...

4) 그런데 모집마감으로 변경하지 못한 사이에 들어온 다른 신청들은 어떻게 하지? 대기중 -> 거절로 변경하자..

5) 팀원들이 그럼 모집 작성자가 신청을 변경하고자 할 때는 어떡해요...? 해서(그러게요....;;;) 기존에 수락과 대기중만 mypage에 나오게 했는데 그냥 다 나오게 하고, 거절도 다시 수락으로 변경할 수 있게 했다... 대신 이때 모집게시글이 마감이 아닐 때만 가능하도록 설정한다.

(나름 팀원들과 열심히 생각해보고 제일 개발하기 편하고, 사용자들에게도 그럭저럭 편한 방법을 생각해본 결과이다...)

 

일단 모집게시글 모델에 현재 인원을 위한 필드를 추가했다.

# 모집게시글 모델
class Join_Article(models.Model):
    join_author = models.ForeignKey(User, verbose_name="작성자", on_delete=models.CASCADE)  #모집 작성자
    join_festival = models.ForeignKey(Festival_Article, verbose_name="축제", on_delete=models.CASCADE)  #모집 축제
    join_title = models.CharField(max_length=20)  #모집 제목
    join_count = models.IntegerField(default=1)  #모집 인원
    join_nowcount = models.IntegerField(default=0)  #현재 모집이 수락된 인원
    join_hits = models.PositiveIntegerField(default=0) #조회수
    join_desc = models.TextField()  #모집 설명
    join_period = models.DateField()  #모집 마감일
    join_status = models.BooleanField(default=True) # true일때 모집중, false 종료
    join_created_at = models.DateTimeField(auto_now_add=True) #모집 게시글 생성 시간
    join_updated_at = models.DateTimeField(auto_now= True) #모집 게시글 수정 시간

 

그리고 일단 모집게시글이 마감 상태이면 신청 버튼이 보이지 않도록 프론트를 변경했다.

// back에서 받아온 json 데이터 front에 내용 붙이는 함수
async function loadDetailArticles(join_article_id) {
	article = await getJoinDetail(join_article_id);
    ...
    if (article.join_status == false) {
    	btnModify.style.visibility = "hidden";
    	btnDelete.style.visibility = "hidden";
    	btnApply.style.visibility = "hidden";
  	} else if (nowuser.user_nickname!=article.join_author) {  //모집게시글 작성자 본인이 아닐 때 수정하기, 삭제하기 버튼이 보이지 않도록
    	btnModify.style.visibility = "hidden";
    	btnDelete.style.visibility = "hidden";
  	} else {  //모집게시글 작성자 본인일 때 신청하기 버튼이 보이지 않도록
    	btnApply.style.visibility = "hidden";
  	}
   	...
}

그리고 거절한 신청 목록도 불러오기 위해 view.py 도 다음과 같이 변경했다. 기존에 있었던 exclude 부분을 뻈다.

# 본인이 작성한 모집게시글에 대한 신청 내역 조회하기(get) 오른쪽
class RecruitedArticleView(APIView):
    def get(self, request):
        user = request.user.id
        myjoins_list = []
        myjoins = Join_Article.objects.filter(join_author_id=user)  #본인이 작성한 모집게시글들
        # myjoin_list = [1, 6, 8] 이런식으로....
        for i in range(len(myjoins)):
            myjoins_list.append(myjoins[i].id)
        #myjoins의 join id와 Recruit_Article의 recruit_join이 일치하는
        #예를들어 join id가 1인 Recruit_Article 찾고, join id가 2인 Recruit_Article 찬고 이런 식으로...,
        
        
        if len(myjoins_list) > 0:
            results = Recruit_Article.objects.filter(recruit_join_id=myjoins_list[0]).distinct()
    
            for j in range(1, len(myjoins_list)):
                results = results.union(Recruit_Article.objects.filter(recruit_join_id=myjoins_list[j]).distinct())
                                        
            if not results.exists():
                    return Response({"message": "작성한 모집글에 대한 신청게시글을 찾을 수 없습니다."}, status=status.HTTP_404_NOT_FOUND)
            elif results.exists():
                    serializer = RecruitSerializer(results, many=True)
                    return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response({"message": "작성한 모집글에 대한 신청게시글을 찾을 수 없습니다."}, status=status.HTTP_404_NOT_FOUND)

 

이제 제일 중요한 수락으로 변경 시 현재 인원을 1증가하고, 거절하면 1을 감소하는 부분을 작성한다. 수락버튼을 1, 거절버튼을 2로 잡았다. 이 부분도 다른 팀원분이 try-except 문으로 변경하면 어떠냐고 하셔서 이후 해당 부분을 잘 정리해 간결화하도록 하겠다.(코드가 너무 길고 복잡한것... 그냥 각 경우를 다 생각했더니 if문으로만 해버려 코드가 지저분해졌다...)

# 신청 상태를 변경하는 뷰(patch)
class RecruitedChangeArticleView(APIView):          
    # 본인이 작성한 모집게시글에 대한 신청 내역 상태 변경하기        
    def patch(self, request, recruit_id, recruit_status):
        recruitpatch = get_object_or_404(Recruit_Article, id=recruit_id) #상태변경을 하고자 하는 신청 객체 불러오기 
        # recruitpatch 예시
        #"id": 3,
        #"recruit_status": 0,
        #"recruit_time": "2022-12-13T11:22:50.661067+09:00",
        #"recruit_user": 1,
        #"recruit_join": 3
        myjoin = get_object_or_404(Join_Article, id=recruitpatch.recruit_join.id)  #신청에 적혀있는 모집게시글 객체 불러오기
        myjoin_recruits = Recruit_Article.objects.filter(recruit_join_id=myjoin.id)  #상태변경을 원하는 신청의 모집게시글 번호에 달린 모든 신청 객체 불러오기
        if myjoin.join_status == False:  #모집게시글이 마감된 경우
        	if request.user == myjoin.join_author:  #신청게시글에 적혀있는 모집게시글의 작성자가 현재사용자라면
                if recruitpatch.recruit_status==1 and recruit_status==1:  #현재신청이 수락인데 수락으로 변경하고자 할 때
                    return Response({"message": "이미 수락되었습니다."}, status=status.HTTP_202_ACCEPTED)
                elif recruitpatch.recruit_status==2 and recruit_status==1:  #현재신청이 거절인데 수락으로 변경하고자 할 때
                    return Response({"message": "모집인원을 초과합니다."}, status=status.HTTP_202_ACCEPTED)
                elif recruitpatch.recruit_status==1 and recruit_status==2:  #현재신청이 수락인데 거절로 변경하고자 할 때
                    recruitpatch.recruit_status = 2  #신청게시글을 거절상태로 변경하고
                    recruitpatch.save()  #저장하고
                    myjoin.join_nowcount -= 1  #모집게시글의 현재 참여인원수를 1감소하고
                    myjoin.join_status = True  #모집가능 상태로 변경하고
                    myjoin.save()  #저장
                    return Response({"message": "신청상태가 거절로 변경되었습니다."}, status=status.HTTP_200_OK)
                elif recruitpatch.recruit_status==2 and recruit_status==2:  #현재신청이 거절인데 거절로 변경하고자 할 때
                    return Response({"message": "이미 거절되었습니다."}, status=status.HTTP_202_ACCEPTED)
                else:  #모집마감 시 미정이 모두 거절로 변경되지만 혹시 모르니까
                    return Response({"message":"모집인원이 마감되었습니다."}, status=status.HTTP_202_ACCEPTED)
           	else:  # 상태변환 권한이 없는 경우
            	return Response({"message": "권한이 없습니다."}, status=status.HTTP_401_UNAUTHORIZED)
        else:  #모집게시글이 진행중일 경우
            # 요청자가 게시글 작성자일 경우에만 수정 가능
            if request.user == myjoin.join_author:  #신청게시글에 적혀있는 모집게시글의 작성자가 현재사용자라면
                if recruit_status == 1:  #수락으로 변경하고자 할 때(버튼)
                    recruitpatch.recruit_status = 1  #신청게시글 상태를 수락으로 변경하고 저장
                    recruitpatch.save()
                    myjoin.join_nowcount += 1  #모집게시글의 현재 참여 인원을 1증가 시키고 저장
                    myjoin.save()
                    if myjoin.join_nowcount == myjoin.join_count:  #방금의 변화로 현재 인원이 정원과 같은지 확인
                        myjoin.join_status = False  #같으면 모집게시글 상태를 마감으로 변경하고 저장
                        myjoin.save()
                        for recruit_obj in myjoin_recruits:  #해당 모집게시글에 달린 모든 신청게시글에 대해
                            if recruit_obj.recruit_status == 0:  #미정 상태는 모두 거절로 변경하고 저장
                                recruit_obj.recruit_status = 2
                                recruit_obj.save()
                    return Response({"message": "신청상태가 수락으로 변경되었습니다."}, status=status.HTTP_200_OK)
                elif recruit_status == 2:  #거절로 변경하고자 할 때(버튼)
                    recruitpatch.recruit_status = 2  #신청게시글 상태를 거절로 변경하고 저장
                    recruitpatch.save()
                    return Response({"message": "신청상태가 거절로 변경되었습니다."}, status=status.HTTP_200_OK)
                else:  # 수락 or 거절 이외의 값 -> 혹시 모르니까
                    return Response({"message": "상태변경을 할 수 없습니다."}, status=status.HTTP_403_FORBIDDEN)
            else:  # 상태변화 권한이 없는 경우
                return Response({"message": "권한이 없습니다."}, status=status.HTTP_401_UNAUTHORIZED)
반응형