TIL_231123_자유게시판

Sol Lee·2023년 11월 23일
0

MVP 기능 완료했고 중간 발표까지 끝남
추가 기능 중 자유게시판 기능을 구현할 차례

자유게시판

요구사항은 다음과 같음

  1. 자유게시판/댓글 CRUD
  2. 사진 여러장 저장 가능하도록
  3. 카테고리로 구분 가능하도록

기본 CRUD 구현은 후닥닥 끝냄

1. 사진 여러장 저장

한 게시글당 여러 사진을 저장할 수 있도록 자유게시글 fk로 저장

게시글/사진 모델 분리

# models.py
class ArticlesFree(models.Model):
    FREE_ARTICLE_CATEGORY = [
        ('review', 'Review'),
        ('chat', 'Chat')
    ]
    author_id = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name="articles_free")
    title = models.CharField(max_length=50)
    content = models.TextField(null=True, blank=True)
    category = models.CharField(max_length=25, choices=FREE_ARTICLE_CATEGORY, default='chat')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.title)
    

class ArticleFreeImages(models.Model):
    article_free_id = models.ForeignKey(ArticlesFree, on_delete=models.CASCADE, related_name="article_free_image", null=True)
    free_image = models.ImageField(blank=True, upload_to="article/free_image")

작성

serializer에 request값을 전달

# view.py
    def post(self, request):
        """ 자유게시판 게시글 작성 """
        if not request.user.is_authenticated:
            return Response({"message": "로그인이 필요합니다."}, status=status.HTTP_401_UNAUTHORIZED)
        if not request.user.is_email_verified:
            return Response({"message": "이메일 인증이 필요합니다."}, status=status.HTTP_403_FORBIDDEN)
        
        serializer = FreeArticleSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            serializer.save(author_id=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

context로 넘겨 받은 request에서 파일 값만 고르고 for문 돌며 저장

# serializers.py
class FreeImagesSerializer(serializers.ModelSerializer):
    class Meta:
        model = ArticleFreeImages
        fields = "__all__"
        
class FreeArticleSerializer(serializers.ModelSerializer):    
    class Meta:
        model = ArticlesFree
        fields = "__all__"
        
    def create(self, validated_data):
    	""" 게시글 등록 + 이미지 저장 """
        free_article = ArticlesFree.objects.create(**validated_data)
        images = self.context['request'].FILES
        for image in images.getlist('image'):
            ArticleFreeImages.objects.create(article_free_id=free_article, free_image=image) 


사진처럼 클라이언트에서 이미지는 전부 키값을 image 로 받기 때문에 images에 {"image": 이미지1, 이미지2...} 처럼 묶여 담기게 됨. getlist()로 하나씩 가져와 저장.

수정

수정할 때 게시글 내용이 수정도기도 하고 사진이 삭제되는 경우도 있고 추가되는 경우도 있음

    def put(self, request, article_free_id):
        """ 자유게시판 특정 게시글+이미지 수정 """
        if not request.user.is_authenticated:
            return Response("로그인 정보가 없습니다", status=status.HTTP_401_UNAUTHORIZED)
        
        free_article = get_object_or_404(ArticlesFree, id=article_free_id)
        if request.user == free_article.author_id:
            # 게시글 수정
            free_article_serializer = FreeArticleSerializer(free_article, data=request.data)
            if free_article_serializer.is_valid():
                free_article_serializer.save()
            else:
                return Response(free_article_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            # 이미지 추가
            new_images = request.FILES
            if new_images:
                for image in new_images.getlist('image'):
                    ArticleFreeImages.objects.create(article_free_id=free_article, free_image=image)
            # 이미지 삭제
            delete_images = request.data.get("delete_image")
            error_text = []
            if delete_images:
                delete_images = eval(delete_images)
                for delete_image in delete_images:
                    try:
                        delete_image_id = ArticleFreeImages.objects.get(id=delete_image, article_free_id=free_article)
                    except ObjectDoesNotExist:
                        error_text.append(f'delete_image_error: db에서 [id:{delete_image}] 이미지 정보를 찾지 못했습니다.')
                    else:
                        delete_image_id.delete()
            return Response({"error_list":error_text, "serializer_data":free_article_serializer.data}, status=status.HTTP_200_OK)
        else:
            return Response("권한이 없습니다", status=status.HTTP_403_FORBIDDEN)

이미지 추가는 저장할 때 처럼 키값을 image 로 받아 저장하고
삭제는 이미지의 delete_image라는 키값으로 이미지의 id값을 리스트로 받아 삭제처리 하도록 구현함.

이미지 삭제할 때 해당 정보를 찾지 못하면 에러 발생하면서 실행이 중지되게 했다가 나머지 요청정보가 사라지게 하지 않기 위해서 그냥 실패시 해당 정보는 건너 뛰고 이미지 삭제 실패한 목록은 텍스트로 전달하도록 고쳐봄. 클라이언트쪽 담당하시는 분이 필요없다구하면.. 지우지 머... 괜찮다구하면 레시피도 리팩토링하면서 이부분 수정해 봐야겠음

2. 카테고리

저번엔 카테고리를 유저단에서도 추가할 수 있도록 별도 모델 생성해서 fk로 연결했는데 이번에 choice 필드 사용해봄

class ArticlesFree(models.Model):
    FREE_ARTICLE_CATEGORY = [
        ('review', 'Review'),
        ('chat', 'Chat')
    ]
	...
    category = models.CharField(max_length=25, choices=FREE_ARTICLE_CATEGORY, default='chat')

클라이언트에서 review/chat 이외에 값을 보내오면 저장 안 됨

추가

새삼 초반에 유효성검사하는게 엄청 반복되는 것 같고 수정할 부분이 많이 보이는 것 같음
리팩토링을 한 번 하긴 해야할 듯
추가기능 다 구현하고 시간있으면 해봐야지

참고

Django choice 필드
DRF-다중-이미지-업로드하기

profile
직업: 개발자가 되고 싶은 오레오 집사

0개의 댓글