SSAFY/Django

[Django] REST - API ( 맛보기 )

황성안 2021. 4. 26. 08:10
728x90

REST API

API

응용 프로그램에서 사용할 수 있도록, 운영체제나 프로그래밍 언어가 제공하는 기능 을 제어할수있게만든 것

프로그램과 다른 프로그램이 제공하는 기능이나 데이터를 사용하기 위한 수단

우체국 우편을 보내기 위해서는 '올바른 주소'

API == 우체국 우편 서비스 ( 어떻게 보내는지는 알필요없다.)

API 명세

API를 사용한다.

Queryset 도 API 이다.

 

HTTP Method 복습하기

자원 URL 구성

http(s)://api.example.com/articles/

 

RESTful API

GET/articles/1/

1번 게시글 검색

POST 생성

POST/users/1/

1번유저가있다라는 뜻 말이 안된다.

 

0427 수업 시작

python -m venv venv
activate
pip install django django_seed djangorestframework
pip freeze > requirements.txt

https://www.django-rest-framework.org/

 

django-admin startproject config .
python manage.py startapp articles

config > settings.py

INSTALLED_APPS = [
    'articles',
    'django_seed',
    'rest_framework',

]

 

article > models.py

from django.db import models

# Create your models here.
class Article(models.Model):
    title = models.CharField(max_length=100)
    content =models.TextField()
python manage.py makemigrations
python manage.py migrate
python manage.py seed articles --number=100

 

config > urls.py

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('articles.urls')),
    # http://ww.kakao.com/api/url 일떄 안붙여준다
]

 

articles > urls.py (생성)

from django.urls import path
from . import views

urlpatterns = [
    path('articles/', views.article_list),

]

 

views.py

from django.shortcuts import renderfrom rest_framework.response import Responsefrom rest_framework.decorators import api_viewfrom .models import Articlefrom .serializers import ArticleSerializer# Create your views here.@api_view()def article_list(request):    # HttpRequest(Django 내부적으로 사용하는 객체)    # HttpRequest + a => api_view    #1. 모든 게시글 가져오고    articles = Article.objects.all()    #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입        #python 기본 타입 => JSON    # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers     # ModelSerializer        #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)    # python api 를 json 으로 변환시키는것을 직렬화라고한다.    serializer = ArticleSerializer(articles, many=True)    #3. 직렬화된 데이터를 응답    # python 기본 타입 => JSON    return Response(data = serializer.data)

 

articles > serializers.py (생성)

https://www.django-rest-framework.org/api-guide/serializers/#modelserializer

from rest_framework import serializersfrom .models import Articleclass ArticleSerializer(serializers.ModelSerializer):    '''    articles 전용    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트    '''    class Meta:        model = Article        fields = ('id', 'title')

 

page not found 뜰경우

Dealing with multiple objects 확인

https://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects

 

api guide views의 [Function Based Views]로 이동

https://www.django-rest-framework.org/api-guide/views/

 

 

views

from django.shortcuts import render, get_object_or_404from rest_framework.response import Responsefrom rest_framework.decorators import api_viewfrom .models import Articlefrom .serializers import ArticleSerializer, ArticleListSerializer# Create your views here.@api_view()def article_list(request):    # HttpRequest(Django 내부적으로 사용하는 객체)    # HttpRequest + a => api_view    #1. 모든 게시글 가져오고    articles = Article.objects.all()    #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입        #python 기본 타입 => JSON    # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers     # ModelSerializer        #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)    # python api 를 json 으로 변환시키는것을 직렬화라고한다.    serializer = ArticleListSerializer(articles, many=True)    #3. 직렬화된 데이터를 응답    # python 기본 타입 => JSON    return Response(data = serializer.data)    @api_view()    def article_detail(request, article_id):        article = get_object_or_404(Article, pk=article_id)        serializer = ArticleSerializer(articles, many=True)        return Response(data=serializer.data)

serializer

from rest_framework import serializersfrom .models import Articleclass ArticleSerializer(serializers.ModelSerializer):    '''    articles 전용    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트    '''    class Meta:        model = Article        fields = ('id', 'title')class ArticleSerializer(serializers.ModelSerializer):    '''    개별 articles 전용    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트    '''    class Meta:        model = Article        fields = ('id', 'title')

 

url.py

from django.urls import pathfrom . import viewsurlpatterns = [    path('articles/', views.article_list),    path('articles/<int:article_id>/', views.article_detail),]

 

views.py

from django.shortcuts import render, get_object_or_404from rest_framework.response import Responsefrom rest_framework.decorators import api_viewfrom .models import Articlefrom .serializers import ArticleSerializer, ArticleListSerializer# Create your views here.@api_view(['GET', 'POST'])def article_list(request):    if request.method == 'GET':        # HttpRequest(Django 내부적으로 사용하는 객체)        # HttpRequest + a => api_view        #1. 모든 게시글 가져오고        articles = Article.objects.all()        #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입                #python 기본 타입 => JSON        # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers         # ModelSerializer                #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)        # python api 를 json 으로 변환시키는것을 직렬화라고한다.        serializer = ArticleListSerializer(articles, many=True)        #3. 직렬화된 데이터를 응답        # python 기본 타입 => JSON        return Response(data = serializer.data)    elif request.method == 'POST':        serializer = ArticleListSerializer(request.data)        if serializer.is_valid():            serializer = serializer.save()            return Response(data=serializer.data)@api_view()def article_detail(request, article_id):    article = get_object_or_404(Article, pk=article_id)    serializer = ArticleSerializer(article)    return Response(data=serializer.data)

image-20210427104904257

 

 

postman 설치하기

https://www.postman.com/downloads/

가입안하고

get 을 post 로 바꾸고 주소입력http://localhost:8000/api/v1/articles/

 

이때

image-20210427105349882

    elif request.method == 'POST':        serializer = ArticleListSerializer(request.data)        if serializer.is_valid():            serializer.save()            return Response(data=serializer.data)

serializer 에서 content 추가

from rest_framework import serializersfrom .models import Articleclass ArticleSerializer(serializers.ModelSerializer):    '''    articles 전용    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트    '''    class Meta:        model = Article        fields = ('id', 'title', 'content')class ArticleListSerializer(serializers.ModelSerializer):    '''    개별 articles 전용    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트    '''    class Meta:        model = Article        fields = ('id', 'title', 'content')

 

 

 

EORROR 띄우기

https://www.django-rest-framework.org/api-guide/status-codes/

에서 400 번대 에러 메세지를 띄우는 곳을 확인한다

또한 잘된다면? successful 200번대를 띄워준다.

views.py

    elif request.method == 'POST':        serializer = ArticleListSerializer(data = request.data)        if serializer.is_valid():            serializer.save()            return Response(data=serializer.data, status=status.HTTP_201_CREATED)#<<<<        return Response(            data=serializer.errors,            status=status.HTTP_400_BAD_REQUEST #<<<<<<<<        )        

 

더 좋은 옵션을 봅시다.

https://www.django-rest-framework.org/api-guide/serializers/ 에서

raise_exception 를 찾아준다.

# Return a 400 response if the data was invalid.serializer.is_valid(raise_exception=True)
@api_view(['GET', 'POST'])def article_list(request):    if request.method == 'GET':        # HttpRequest(Django 내부적으로 사용하는 객체)        # HttpRequest + a => api_view        #1. 모든 게시글 가져오고        articles = Article.objects.all()        #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입                #python 기본 타입 => JSON        # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers         # ModelSerializer                #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)        # python api 를 json 으로 변환시키는것을 직렬화라고한다.        serializer = ArticleListSerializer(articles, many=True)        #3. 직렬화된 데이터를 응답        # python 기본 타입 => JSON        return Response(data = serializer.data)    elif request.method == 'POST':        serializer = ArticleListSerializer(data = request.data)        if serializer.is_valid(raise_exception=True): #<<<<<<<<<<<<<<<<<<<<<            serializer.save()            return Response(data=serializer.data, status=status.HTTP_201_CREATED)        return Response(            data=serializer.errors,            status=status.HTTP_400_BAD_REQUEST        )        

 

 

특정 게시글 삭제

일반적으로 삭제된후에는 상태로 HTTP_204_NO_CONTENT를 해줌

https://www.django-rest-framework.org/api-guide/status-codes/

@api_view()def article_detail(request, article_id):    article = get_object_or_404(Article, pk=article_id)    if request.method == 'GET':        # 넘겨도 상관x 구분해서하라 요청 로직 다르다.        # 단일 객체 many x        serializer = ArticleSerializer(article)        return Response(data=serializer.data)    elif request.method == 'DELETE':        article = article.delete()        data = {            'message':f'{article}이 삭제되었습니다.'        }        return Response(data=data, status=status.HTTP_204_NO_CONTENT)

 

 

수정하기

image-20210427113054319

 

 

 

models.py

from django.db import models# Create your models here.class Article(models.Model):    title = models.CharField(max_length=100)    content =models.TextField()class Comment(models.Model):    article = models.ForeignKey(Article, on_delete=models.CASCADE)    content = models.CharField(max_length=100)

 

urls.py

from django.urls import pathfrom . import viewsurlpatterns = [    path('articles/', views.article_list),    path('articles/<int:article_id>/', views.article_detail),    path('comments/',views.comment_list),    # ]

 

views.py

from rest_framework.response import Responsefrom rest_framework.decorators import api_viewfrom rest_framework import statusfrom django.shortcuts import render, get_object_or_404from .models import Article, Commentfrom .serializers import (    ArticleSerializer,    ArticleListSerializer,    CommentSerializer,)# Create your views here.@api_view(['GET', 'POST'])def article_list(request):    if request.method == 'GET':        # HttpRequest(Django 내부적으로 사용하는 객체)        # HttpRequest + a => api_view        #1. 모든 게시글 가져오고        articles = Article.objects.all()        #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입                #python 기본 타입 => JSON        # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers         # ModelSerializer                #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)        # python api 를 json 으로 변환시키는것을 직렬화라고한다.        serializer = ArticleListSerializer(articles, many=True)        #3. 직렬화된 데이터를 응답        # python 기본 타입 => JSON        return Response(data = serializer.data)    elif request.method == 'POST':        serializer = ArticleListSerializer(data = request.data)        if serializer.is_valid(raise_exception=True):            serializer.save()            return Response(data=serializer.data, status=status.HTTP_201_CREATED)        return Response(            data=serializer.errors,            status=status.HTTP_400_BAD_REQUEST        )        @api_view(['GET', 'DELETE','PUT'])def article_detail(request, article_id):    article = get_object_or_404(Article, pk=article_id)    if request.method == 'GET':        # 넘겨도 상관x 구분해서하라 요청 로직 다르다.        # 단일 객체 many x        serializer = ArticleSerializer(article)        return Response(data=serializer.data)    elif request.method == 'DELETE':        article = article.delete()        data = {            'message': f'{article}이 삭제되었습니다.'        }        return Response(data=data, status=status.HTTP_204_NO_CONTENT)    elif request.method == 'PUT':        serializer = ArticleSerializer(data=request.data)        if serializer.is_valid(raise_exception=True):            serializer.save()            return Response(data=serializer.data)@api_view()def comment_list(request):    comments = Comment.objects.all()    serializer = CommentSerializer(comments, many = True)    return Response(data=serializer.data)

 

 

postman 들어가서 확인하기

get http://localhost:8000/api/v1/articles/102/

article > urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('articles/', views.article_list),
    path('articles/<int:article_id>/', views.article_detail),

    path('comments/',views.comment_list),
    path('articles/<int:article_id>/comments/', views.create_comment)# 댓글 생성
    # 
]

views.py

(serializer 는 commit 이 없습니다.) https://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save

from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status

from django.shortcuts import render, get_object_or_404

from .models import Article, Comment
from .serializers import (
    ArticleSerializer,
    ArticleListSerializer,
    CommentSerializer,
)


# Create your views here.
@api_view(['GET', 'POST'])
def article_list(request):
    if request.method == 'GET':
        # HttpRequest(Django 내부적으로 사용하는 객체)
        # HttpRequest + a => api_view

        #1. 모든 게시글 가져오고
        articles = Article.objects.all()
        #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입
        
        #python 기본 타입 => JSON
        # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers 
        # ModelSerializer
        
        #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)
        # python api 를 json 으로 변환시키는것을 직렬화라고한다.
        serializer = ArticleListSerializer(articles, many=True)
        #3. 직렬화된 데이터를 응답
        # python 기본 타입 => JSON
        return Response(data = serializer.data)

    elif request.method == 'POST':
        serializer = ArticleListSerializer(data = request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(
            data=serializer.errors,
            status=status.HTTP_400_BAD_REQUEST
        )
        

@api_view(['GET', 'DELETE','PUT'])
def article_detail(request, article_id):
    article = get_object_or_404(Article, pk=article_id)

    if request.method == 'GET':
        # 넘겨도 상관x 구분해서하라 요청 로직 다르다.
        # 단일 객체 many x
        serializer = ArticleSerializer(article)
        return Response(data=serializer.data)

    elif request.method == 'DELETE':
        article = article.delete()
        data = {
            'message': f'{article}이 삭제되었습니다.'
        }

        return Response(data=data, status=status.HTTP_204_NO_CONTENT)

    elif request.method == 'PUT':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data)

@api_view()
def comment_list(request):
    comments = Comment.objects.all()
    serializer = CommentSerializer(comments, many = True)
    return Response(data=serializer.data)

@api_view(['POST'])
def create_comment(request, article_id):
    article = get_object_or_404(Article, pk=article_id)

    #일단 바인딩 > 
    serializer = CommentSerializer(data=request.data)
    if serializer.is_valid(raise_exception=True):
        serializer.save(article=article) # 게시글 설정
        return Response(data=serializer.data)

 

모든 댓글 보기

GET http://localhost:8000/api/v1/comments/ 모든 커멘트 확인하기

 

https://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields

serializers.py

class CommentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = ('id', 'content', 'article')
        read_only_fields = ['account_name'] #<<<<<<<<< 추가

 

 

게시글에서 댓글을 전부가져오고싶을떄

https://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations

serializers.py 수정

from rest_framework import serializers
from .models import Article, Comment



class CommentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = ('id', 'content', 'article')
        # fields에 작성된 필드들은
        # 유효성 검사의 대상이 됩니다.
        # (== is_valid()를 호출했을 때의 검사 대상)
        read_only_fields = ['article']

class ArticleSerializer(serializers.ModelSerializer):
    '''
    articles 전용
    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트
    '''
    # 커멘트를 위로보내주자.
    comment_set = CommentSerializer(many=True, read_only=True)

    class Meta:
        model = Article
        fields = ('id', 'title', 'comment_set')


class ArticleListSerializer(serializers.ModelSerializer):
    '''
    개별 articles 전용
    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트
    '''
    class Meta:
        model = Article
        fields = ('id', 'title', 'content')

 

 

댓글 필드에 숫자 적인 필드를 담고싶을떄

 

comment_count = serializers.IntegerField() #추가해주기

 

from rest_framework import serializers
from .models import Article, Comment


class CommentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = ('id', 'content', 'article')
        # fields에 작성된 필드들은
        # 유효성 검사의 대상이 됩니다.
        # (== is_valid()를 호출했을 때의 검사 대상)
        read_only_fields = ['article']

class ArticleSerializer(serializers.ModelSerializer):
    '''
    articles 전용
    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트
    '''
    # 커멘트를 위로보내주자.
    comment_set = CommentSerializer(many=True, read_only=True)
    #커스텀 필드, 필요한 정보는 저눕 넣을수있다. 
    #총 몇개의 정보를 담을수있을까?
    comment_count = serializers.IntegerField(source='comment_set.count', read_only=True)

    class Meta:
        model = Article
        fields = ('id', 'title', 'comment_set', 'comment_count')


class ArticleListSerializer(serializers.ModelSerializer):
    '''
    개별 articles 전용
    모델을 어떻게 직렬화할 것인지 설정하는 것이 포인트
    '''
    class Meta:
        model = Article
        fields = ('id', 'title', 'content')



 

 

글수정하기

put

http://localhost:8000/api/v1/articles/10/

리드온리 트루가없으면 수정할떄 비어있다고떠서 에러가뜹니다.

 

 

 

 

 

 

 

 

COmment Detail 부분

댓글 삭제하기

from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status

from django.shortcuts import render, get_object_or_404

from .models import Article, Comment
from .serializers import (
    ArticleSerializer,
    ArticleListSerializer,
    CommentSerializer,
)


# Create your views here.
@api_view(['GET', 'POST'])
def article_list(request):
    if request.method == 'GET':
        # HttpRequest(Django 내부적으로 사용하는 객체)
        # HttpRequest + a => api_view

        #1. 모든 게시글 가져오고
        articles = Article.objects.all()
        #QuerySet ( 장고가 만든 하나의 타입 ) => python 기본 타입
        
        #python 기본 타입 => JSON
        # 공식문서(https://www.django-rest-framework.org/) > API CUIDE > Serializers 
        # ModelSerializer
        
        #2. 직렬화 ( 파이선 api 와 자바 api 서로 데이터 통신하기위해 규격이필요하는데 그것이 json, xml 이다.)
        # python api 를 json 으로 변환시키는것을 직렬화라고한다.
        serializer = ArticleListSerializer(articles, many=True)
        #3. 직렬화된 데이터를 응답
        # python 기본 타입 => JSON
        return Response(data = serializer.data)

    elif request.method == 'POST':
        serializer = ArticleListSerializer(data = request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(
            data=serializer.errors,
            status=status.HTTP_400_BAD_REQUEST
        )
        

@api_view(['GET', 'DELETE','PUT'])
def article_detail(request, article_id):
    article = get_object_or_404(Article, pk=article_id)

    if request.method == 'GET':
        # 넘겨도 상관x 구분해서하라 요청 로직 다르다.
        # 단일 객체 many x
        serializer = ArticleSerializer(article)
        return Response(data=serializer.data)

    elif request.method == 'DELETE':
        article = article.delete()
        data = {
            'message': f'{article}이 삭제되었습니다.'
        }

        return Response(data=data, status=status.HTTP_204_NO_CONTENT)

    elif request.method == 'PUT':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data)

@api_view()
def comment_list(request):
    comments = Comment.objects.all()
    serializer = CommentSerializer(comments, many = True)
    return Response(data=serializer.data)

@api_view(['POST'])
def create_comment(request, article_id):
    article = get_object_or_404(Article, pk=article_id)

    #일단 바인딩 > 
    serializer = CommentSerializer(data=request.data)
    if serializer.is_valid(raise_exception=True):
        serializer.save(article=article) # 게시글 설정
        return Response(data=serializer.data)



@api_view(['GET', 'DELETE', 'PUT'])
def comment_detail(request, comment_id):
    '''
    생성(POST)는 안된다 
    http://localhost:8000/api/v1/comments/<int:comment_id>/
    '''    
    comment = get_object_or_404(Comment, pk=comment_id)

    if request.method == 'GET':
        #커멘트시리얼라이즈에서 반환
        serializer = CommentSerializer(comment)
        return Response(data = serializer.data)

    elif request.method == 'DELETE':
        comment.delete()
        data = {
            'message': '성공적으로 삭제되었습니다.'
        }
        return Response(data=data, status= status.HTTP_204_NO_CONTENT)
    
    elif request.method == 'PUT':
        serializer = CommentSerializer(comment, data=request.data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(data=serializer.data)


 

 

 

728x90

'SSAFY > Django' 카테고리의 다른 글

[Django] Dom  (0) 2021.04.28
[Django] swagger  (0) 2021.04.27
[Django] 좋아요, follow, hashtag 간단 코딩  (0) 2021.04.01
[Django] 로그인한 사용자 판별하기  (0) 2021.03.27
[Django] 댓글 삭제  (0) 2021.03.26