TIL(22/12/01)

김규현·2022년 12월 3일
0

💻 Today I Learned

팀 프로젝트의 커뮤니티 CRUD 기능을 구현하고 포스트맨으로 테스트 하던 중 게시글을 작성하는 과정에서 user 필드를 아래와 같이 필수로 입력하라는 메시지가 출력되었다.

우선 모델과 views, serializer 코드는 아래와 같이 작성하였다.

# models.py
class Article(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='article_user')
    category = models.ForeignKey(Hobby, on_delete=models.CASCADE, related_name='article_category')
    title = models.CharField(max_length=500)
    content = models.TextField()
    article_image = models.ImageField(upload_to='media/article/', null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.title)
        
# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = "__all__"
# views.py
class ArticleCreateView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def post(self, request):
        if not request.user.is_authenticated:
            return Response({"msg":"로그인이 필요합니다!"}, status=status.HTTP_401_UNAUTHORIZED)
        
        serialzier = ArticleSerializer(data=request.data)
        if serialzier.is_valid():
            serialzier.save()
            return Response(serialzier.data, status=status.HTTP_201_CREATED)
        return Response(serialzier.errors, status=status.HTTP_400_BAD_REQUEST)

현재 문제는 게시글을 작성할 때 user를 정보를 직접 입력해서 요청보내야 하는 것이 문제인데, 원인은 Article 모델에 user가 ForeignKey로 연결되어 있고, serializer의 fields가 "__all__"로 설정되어 있기 때문에 fields에 user도 포함되어 입력해야 하도록 설정된 것이다.

이렇게 진행할 경우 프론트에서 게시글을 작성하는 해당 API에 HTTP 요청을 보낼 때 user 정보를 body에 넣어서 보내주어야 한다.

다른 방법으로는 serializer의 fields에서 Article 모델에 있는 필드 중 user를 제외하고 입력한 후 views에서 serializer를 save할 때 아래와 같이 user를 request.user로 설정해주면 된다.

def post(self, request):
	serialzier = ArticleSerializer(data=request.data)
    if serialzier.is_valid():
    	serialzier.save(user=request.user)
        return Response(serialzier.data, status=status.HTTP_201_CREATED)
    return Response(serialzier.errors, status=status.HTTP_400_BAD_REQUEST)

두 가지 방법 중 어떤 방법이 좋을지 생각해본 결과 serializer에 user를 포함하면 프론트에서 body에 user 정보를 실어 보내주어야하고, 포함하지 않으면 views에서 serializer를 save 할 때 user를 request.user로 요청 보낸 사람이 user가 되는 것인데 그냥 둘 다 해주면 될 것 같다.

우리 프로젝트에서 게시글은 로그인된 유저만 작성이 가능하고, 프론트에서 유저를 정의하냐 혹은 백엔드에서 유저를 정의하냐 차이를 두고 고민을 했던 것 같은데 그냥 프론트에서는 localstorage에 저장된 access 토큰의 user 정보를 꺼내어 바디에 실어보내고, 백엔드에서는 permission을 설정하고, 다른 내용과 함께 유저 정보를 받으면 될 것 같다.

결론은 아래와 같다.

# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
# SerializerMethodfield를 사용하여 user object의 return 값을 nickname으로 커스텀
	user = serializer.SerializerMethodfield()
    
    def get_user(self, obj):
         return obj.user.nickname
         
	class Meta:
        model = Article
        fields = "__all__"
        
# views.py
class ArticleCreateView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def post(self, request):
        if not request.user.is_authenticated:
            return Response({"msg":"로그인이 필요합니다!"}, status=status.HTTP_401_UNAUTHORIZED)
        
        serialzier = ArticleSerializer(data=request.data)
        if serialzier.is_valid():
            serialzier.save(user=request.user)
            return Response(serialzier.data, status=status.HTTP_201_CREATED)
        return Response(serialzier.errors, status=status.HTTP_400_BAD_REQUEST)
// request/HTTP Body
{
    "title":"테스트",
    "content":"내용",
    "category":"1",
    "user":"test@test.com"
}
profile
웹개발 회고록

0개의 댓글