본문 바로가기
DEV/Web 개발

Web 개발 :: 파이썬 Django Rest Framework(8) _ 게시글 생성

by 올커 2022. 11. 1.

DRF(Django Rest Framework)(8) _ 게시글 생성

01. 게시글 기본 환경 세팅하기

 - 지난번 포스팅에 이어 게시글 환경을 만들고자 한다.

 - django 프로젝트로 돌아와서 articles라는 앱을 생성하고, urls, views, models를 정의해준다.

# articles/urls.py

from django.urls import path
from articles import views


urlpatterns = [
    path('', views.ArticleView.as_view(), name='article_view'),
    path('<int:article_id>/', views.ArticleDetailView.as_view(), name='article_detail_view'),
    path('comment/', views.CommentView.as_view(), name='comment_view'),
    path('comment/<int:comment_id>/', views.CommentDetailView.as_view(), name='comment_detail_view'),
    path('like/', views.LikeView.as_view(), name='like_view'),
]
# articles/views.py

from rest_framework import status, permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleListSerializer


class ArticleView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass


class ArticleDetailView(APIView):
    def get(self, request, article_id):
        pass

    def put(self, request, article_id):
        pass

    def delete(self, request, article_id):
        pass

class CommentView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass

class CommentDetailView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass

class LikeView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass
# articles/models.py

from django.db import models
from users.models import User


class Article(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=50)
    content = models.TextField()
    image = models.ImageField(blank=True, upload_to='%Y/%m/')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

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

 - models에서는 이미지를 업로드, 관리하기 때문에 Pillow 라이브러리를 추가 설치해준다.

pip install Pillow

 - ImageField에서는 null은 작동되지 않는다. 빈 이미지를 허용할 경우 blank=True로 해주면 된다.

 

 - 또, FileField나 ImageField를 사용할 때에는 MEDIA_ROOT, MEDIA_URL을 추가 설정해주어야 하고, upload_to라는 옵션을 사용하여 MEDIA_ROOT 아래 sub directory로 보내줄 수 있도록 한다. 해당 이미지의 url을 사용할 경우 {{object.파일명.url}}을 통해 불러올 수 있다. (※ 참고 링크1, 링크2)

 

# settings.py

STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / "static"

MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / "media"
# urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/', include('users.urls')),
    path('articles/', include('articles.urls')),
]

# settings.py 에서 DEBUG = True일 경우(개발단계)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

02. 세부 기능 만들기_게시글 가져오기

 - views.py의 ArticleView를 아래와 같이 수정한다.

class ArticleView(APIView):
    # 게시글 전체 불러오기
    def get(self, request):
        articles = Article.objects.all()
        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        pass

 - serializers.py를 생성하고 아래와 같이 입력해준다. 여기서 ArticleSerializer는 기존에 알고있던 것처럼 모든 필드를 가져오지만, 몇 가지 필드만 선택해서 가져오고자 할 때에는 ArticleListSerializer처럼 튜플형태로 넣어서 가져온다.

# articles/serializers.py

from rest_framework import serializers

from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = '__all__'

# serializer 필드의 일부만 가져오도록 설정하기
class ArticleListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('pk', 'title', 'image', 'updated_at', 'user')

  - 포스트맨에서 articles라는 collection을 만들고, articles list라는 request를 만들어 찍어보면 아래와 같이 확인할 수 있다.

  - 포스트맨에서 user값이 id로 나오는 것을 email로 변경해주고자 한다면 다음 코드를 참고하면 된다. 

# articles/serializers.py

class ArticleListSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()

    def get_user(self, obj):
        return obj.user.email

    class Meta:
        model = Article
        fields = ('pk', 'title', 'image', 'updated_at', 'user')

 - user라는 attribute에 serializers.SerializerMethodField()를 할당하고, get_user라는 함수에 self, obj를 넣어 정의한다. 여기서 obj는 Article이 되고, user의 email을 get_user에서 리턴하면서 이 해당값이 user로 들어가게 된다. 조금 복잡해보이는데 결론적으로 아래 그림의 붉은 박스처럼 user에 email값이 들어가게 되는 것이다.

 


03. 세부 기능 만들기_게시글 생성하기

 - views.py의 ArticleView의 post 함수를 아래와 같이 수정한다.

# articles/views.py

class ArticleView(APIView):
    def post(self, request):
            serializer = ArticleSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            else:
                return Response(serializer.errors)

 - 포스트맨으로 POST를 테스트해보고자 한다. 일단 아무것도 쓰지 않고 send버튼을 누르면 아래와 같이 요구되는 필드가 나온다. title, content항목은 작성하면되는데, user는 가져오는 방법이 별도로 있다.

 - user를 가져오기 위해서는 포스트맨에서 이전에 만들어놓은 login 리퀘스트를 실행하여 access 토큰값을 가져와서 article create 리퀘스트의 헤더에 붙여넣어야 한다. 그런데 이걸 매번 붙여넣기 번거로우니 Environments를 활용해서 local에 정의해두려한다. variable의 이름은 token으로 짓고 initial value에 access 토큰값을 복사해와서 붙여넣어준다.

 - 그 후 article create 리퀘스트의 Headers부분으로 돌아와서 아래와 같이 작성해준다.

 - 추가로 serializers.py에서 ArticleCreateSerializer를 아래와 같이 생성해주고, views.py의 post 함수에서 serializer.save()에 user를 request.user로 받아오게 한다.

# articles/serializers.py

class ArticleCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('title', 'image', 'content')
# articles/views.py

class ArticleView(APIView):
	# 게시글 생성하기
    def post(self, request):
        serializer = ArticleCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

 - 이를 완료하면 게시글 생성이 정상적으로 동작하는 것을 확인할 수 있다.

 - 그렇지만 아직 이미지는 않넣어봐서 null이다. 이미지를 넣으려면 Body -> form-data 로 들어가서 key에 image를 작성하고 key 필드 우측에 마우스를 대면 속성이 나오는데 File로 선택한다. 그럼 Value란에서 이미지를 업로드할 수 있게 된다. Send를 누르면 아래와 같이 정상적으로 이미지가 등록되는 것을 확인할 수 있다.

 - 마지막으로 위에서 정리하지 않았던 status를 아래와 같이 정리해주었다.

# articles/views.py

...
class ArticleView(APIView):
	# 게시글 생성하기
    def post(self, request):
        serializer = ArticleCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data, status.HTTP_200_OK)
        else:
            return Response(serializer.errors, stutus=status.HTTP_400_BAD_REQUEST)

 

반응형

댓글