팀 프로젝트의 커뮤니티 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"
}