본문 바로가기
부트캠프TIL, WIL/AI웹개발(스파르타코딩클럽)

[AI웹개발][61일차TIL] Django 백엔드 CRUD 배우기

by 우지uz 2023. 6. 13.

AI 웹개발 - 61일차 TIL :  Django 백엔드 CRUD 배우기 . 6월 12일 월요일

개요
1. 오늘 배운 것 
1-1 . 게시글 CRUD
1-2 . PERMISSION_CLASSES 이용
2. 느낀점

1. 오늘 배운 것

1-1. CRUD - 장고 실무 심화 [권기현 튜터] 2~4주차 내용

# 게시글 뷰, 게시글 id 값(article_id)를 굳이 받아오지 않아도 되는 뷰
class ArticleView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    # 게시글 전체 보여주기
    def get(self, request):
        articles = Article.objects.all().order_by("-created_at")
        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
	# 게시글 작성하기
    def post(self, request):
        serializer = ArticleCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# 게시글 디테일 뷰, 게시글 id 값(article_id)를 꼭 받아와야 하는 뷰
class ArticleDetailView(APIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    # 게시글 id 에 맞게, 게시글 하나하나 상세하기 눌러서 봐야하는 페이지
    def get(self, request, article_id):
        article = get_object_or_404(Article, id=article_id)
        serializer = ArticleDetailSerializer(article)
        return Response(serializer.data, status=status.HTTP_200_OK)
	# 게시글 id를 받아와서, 게시글을 수정할 때 쓰는 뷰
    def put(self, request, article_id):
        article = get_object_or_404(Article, id=article_id)
        if request.user == article.user:
            serializer = ArticleCreateSerializer(article, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status.HTTP_200_OK)
            else:
                return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
        else:
            return Response({'message':'권한이 없습니다.'}, status.HTTP_403_FORBIDDEN)
	# 게시글id를 받아와서, 특정 게시글을 삭제하는 뷰
    def delete(self, request, article_id):
        article = get_object_or_404(Article, id=article_id)
        if request.user == article.user:
            article.delete()
            return Response({"message": "삭제완료!"}, status=status.HTTP_204_NO_CONTENT)
        else:
            return Response({'message':'권한이 없습니다.'}, status=status.HTTP_403_FORBIDDEN)

여기서 핵심적인 부분들만 설명을 드리겠습니다. (permission클래스는 곧 설명할 예정)

첫째로,

articles = Article.objects.all().order_by("-created_at")

- 여기서 articles 라는 변수를 우리가 임의로 지정 했습니다. 
- Article모델을 불러오고, 거기서 objects 는 Article 인스턴스를 불러오는 쿼리셋 매니저(Queryset Manager)입니다. 
    Article을 여러개 작성했다면, 1번 게시글, 2번 게시글, 3번 게시글 등등 여러 게시글들이 있습니다. 
- Article.objects.all() 는 모든 게시글들을 불러와 준다는 이야기 입니다. 

더보기

게시글 전체보기http://127.0.0.1:8000/article/

**`GET** /article/`

**`HTTP 200 OKAllow:** GET, POST, HEAD, OPTIONS
**Content-Type:** application/json
**Vary:** Accept

[
    {
        "id": 8,
        "title": "7번째 게시",
        "content": "게시글을 작서앻ㅆ습니",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 7,
        "title": "6th article create",
        "content": "i posted 6th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 6,
        "title": "5th article create",
        "content": "i posted 5th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 5,
        "title": "4th article create",
        "content": "i posted 4th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 4,
        "title": "3th article create",
        "content": "i posted 3th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 3,
        "title": "2th article create",
        "content": "i posted 2th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 2,
        "title": "2th article create",
        "content": "i posted 2th article",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": []
    },
    {
        "id": 1,
        "title": "첫번째 게시글입니다",
        "content": "첫 게시글은 게시글을 어드민페이지에 등록했다는 것을\r\n적습니다",
        "user": {
            "id": 1,
            "account": "ksw4060",
            "nickname": "ksw",
            "profile_img": ""
        },
        "hearts": [
            2
        ]
    }
]`

- order_by("-created_at") 은 최근에 작성한 글을 가장 먼저 나타나게 하는 순서를 말합니다.

그 다음

serializer = ArticleListSerializer(articles, many=True)

우리는 articles 라는 여러 게시글들을 쿼리셋 매니저로 불러와줬기 때문에
many=True 라는 옵션을 꼭 붙여 줘야합니다. 

objects.all()과 many=True 라는 옵션은 항상 붙어다닙니다. 
그 다음에

def post(self, request):
        serializer = ArticleCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user=request.user)
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

여기서 post 메소드는 게시글을 작성하는 함수입니다. 
get 메소드와 다른 점은, get 은 이미 작성되어 있는 게시글들을 조회하는 역할 이지만

post 메소드는 이미 작성되어 있는 게시글이 아닌, 새롭게 게시글을 작성하는 함수이기에
objects 쿼리셋 매니저로 게시글 정보들을 가져올 필요가 없습니다. 

request 유저가 입력한 데이터를 바탕으로,
serializer JSON 데이터로 직렬화해서

serializer = ArticleCreateSerializer(data=request.data)

저장해주면 됩니다. 

if serializer.is_valid():
    serializer.save(user=request.user)
    return Response(serializer.data, status=status.HTTP_200_OK)

 


1-2. permission_classes 이용하기

제가 사용한 permission_classes 은 총 3가지 입니다. 

로그인 하지 않은 유저에 대해서는 게시글 작성(POST)이 아닌, 읽기(GET)만 가능하도록 하는 

permission_classes = [permissions.IsAuthenticatedOrReadOnly]

로그인 한 유저에 대해서 가능하도록 하는 

permission_classes = [permissions.IsAuthenticated]

관리자 유저에게만 상품 리뷰 및 문의에 대해 답변을 허용하게 해주는 

permission_classes = [permissions.IsAdminUser]

입니다. 

 

이외에 다양한 퍼미션 클래스가 있지만, 너무 많기 때문에 

공식 문서 링크를 남기고 떠나겠습니다 ㅎㅎ;; 
https://www.django-rest-framework.org/api-guide/permissions/


2. 느낀점

CRUD 에 대한 연습을 많이, 깊게, 다양하게 해볼 필요가 있다고 생각 됩니다. 

CRUD 해야하는 HTTP METHOD 에는 총 5가지가 있는데
GET, POST, PATCH, PUT, DELETE 

기능에 따라, 인자로 어떤 것을 받아와야 하는지가 다를 것이고

주어진 인자 조건에 따라, 어떤 로직을 구현해야 하는지
생각하게 되었습니다.  

다음 게시글에서는, 쇼핑몰 상품에 대한 CRUD를 다루도록 하겠읍니다아아!