본문 바로가기
스파르타코딩 AI웹개발 3기

내일배움캠프_TIL_2022.10.27

by 청귤에이드 2022. 10. 28.

오늘의 코드 [2022.10.27]

중요해서 반드시 기억할 필요가 있거나, 주의해야  코드를 답안 형식으로 저의 코멘트와 함께 정리해 보았습니다.

 

Q. Django Rest Framework

 

<데코레이터 함수>

-       튜터님의 파이썬 데코레이터 function 강의 참조

# 예시


def wrapper_function(func):

    def decorated_function():

        print("함수 이전에 실행")

        func()

        print("함수 이후에 실행")

    return decorated_function

 

def basic_function():

    print("실행하고자 하는 함수")

 

new_function = wrapper_function(basic_function)

 

new_function()
# 출력 결과

 

함수 이전에 실행

실행하고자 하는 함수

함수 이후에 실행

 

기존에 함수 안에 함수를 집어넣은 결과를 출력하고자 할 때 다음과 같이 작성하였다면

 

# 예시

 

def wrapper_function(func):

    def decorated_function():

        print("함수 이전에 실행")

        func()

        print("함수 이후에 실행")

    return decorated_function




@wrapper_function

def basic_function():

    print("실행하고자 하는 함수")
# 출력 결과

 

함수 이전에 실행

실행하고자 하는 함수

함수 이후에 실행

 

위와 같이 ‘@’를 추가하여 상위 결과에 해당하는 함수를 입력하면, wrapper_function 함수 내에 basic_function 함수가 입력된다.

 

<Serializer를 이용한 데이터 조회>

Articles/views.py에서

from rest_framework.response import Response

from rest_framework.decorators import api_view

from articles.models import Article

from articles.serilaizers import ArticleSerializer

 

@api_view(['GET'])

def index(request):

    articles = Article.objects.all()

    article = articles[0]

    serializer = ArticleSerializer(article)

    return Response(serializer)

 

이렇게 작성하면 다음과 같은 assertion error가 발생하므로

데이터를 올바르게 가져오기 위해서는 아래와 같이 serializer .data를 붙여주어야 한다.

@api_view(['GET'])

def index(request):

    articles = Article.objects.all()

    article = articles[0]

    serializer = ArticleSerializer(article)

    return Response(serializer.data)

 

실제로 data를 클릭하면 rest_framework/serializers.py에 다음과 data 함수로 이동하는 것을 알 수 있음

    @property

    def data(self):

        ret = super().data

        return ReturnDict(ret, serializer=self)

 

(Articles/views.py에서)

여러 개의 데이터 셋을 나타나게 하기 위해서는 변수(articles) 뒤에 ‘many=True’를 붙여주는 것을 잊지 말자 (그렇지 않으면 오류 발생)

@api_view(['GET'])

def index(request):

    articles = Article.objects.all()

    serializer = ArticleSerializer(articles, many=True)

    return Response(serializer.data)

 

articles/models.py에서

    content = models.TextField(null=True, blank=True)

null blank True를 지정해 주어야 훗날 content 작성 시 오류가 발생하지 않음

 

from rest_framework import status

from rest_framework.response import Response

from rest_framework.decorators import api_view

from articles.models import Article

from articles.serilaizers import ArticleSerializer

 

@api_view(['GET', 'POST'])

def index(request):

    if request.method == 'GET':

        articles = Article.objects.all()

        serializer = ArticleSerializer(articles, many=True)

        return Response(serializer.data)

    elif request.method == 'POST':

        serializer = ArticleSerializer(data = request.data)

        if serializer.is_valid():

            serializer.save()

            return Response(serializer.data, status=status.HTTP_201_CREATED)

        else:

            print(serializer.errors)

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

 

 

- 이전에 로그인 화면 작성했을 때처럼 GET, POST 방식에 맞춰 작성

- GET 방식은 serializer를 통해 articles를 불러오도록(Response) 구성

- POST 방식에서 serializer에서 ArticleSerializer(request.data)라고 착각하기 쉬운데 반드시 data = request.data 형태로 입력해야 한다. 또한, .save()로 저장하기 전에 반드시 유효성 검사 .is_valid()를 해주어야 한다. Response 뒤에 status = status. 하여 호출하고자 하는 HTTP 응답을 지정할 수도 있다.

 

@api_view(['GET','PUT','DELETE'])

def article_view(request, article_id):

    if request.method =='GET':

        article = get_object_or_404(Article, id=article_id)

        serilaizers = ArticleSerializer(article)

        return Response(serilaizers.data)

 

get_object_or_404 를 통해 url에서 articles/(임의의 숫자)를 입력해도 바로 오류 창이 뜨는 것이 아닌, 아래와 같이 나타남을 알 수 있다.

 

게시물 수정에 해당하는 PUT 방식의 경우, serializers GETPOST 방식을 혼용한 듯한 구조를 보이는데 ArticleSerializer(article, data=request.data) 는 기존 데이터(article)에서 클라이언트에서 수정된 데이터(data=request.data)로 바꿈을 의미하며 이를 serializer가 인식한다.

 

@api_view(['GET','PUT','DELETE'])

def article_view(request, article_id):

    if request.method =='GET':

        article = get_object_or_404(Article, id=article_id)

        serilaizer = ArticleSerializer(article)

        return Response(serilaizer.data)

    elif request.method == 'PUT':

        article = get_object_or_404(Article, id=article_id)

        serilaizer = ArticleSerializer(article, data = request.data)

        if serilaizer.is_valid():

            serilaizer.save()

            return Response(serilaizer.data)

 

DELETE 방식을 추가할 때는 데이터를 불러오지 않으므로 serializer가 필요하지 않다.

    elif request.method == 'DELETE':

        article = get_object_or_404(Article, id=article_id)

        article.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

 

url에서 기존에 127.0.0.1:8000/articles/index에서 index를 경로에서 제외하고 싶을 때, 아래와 같이 path에서 “” 빈칸으로 두면 된다. (“/” 으로 헷갈리지 않도록 주의)

urlpatterns = [

    path("",views.articleAPI, name="index"),

    path("<int:article_id>/",views.articleDetailAPI, name="article_view"),

]

 

(번외편) 포스트맨 사용 시, 훗날 Environments에서 local:host 지정 시 ‘INITIAL VALUE’ URL 입력할 땐, 가령 http://127.0.0.1:8000 처럼 뒤에 슬래시 없이 입력하는 것을 권장한다. Collections request에서 Enter request URL 작성 시, {{host}}/…/ 슬래시 때문에 오류날수 있음(본인도 그것 땜에 시간 많이 소비함..)