dJango로 restful API 서버만들기 [2] - rest framework 적용

     

이전 글 2019/10/14 - [Study/python] - dJango로 restful API 서버만들기 [1] - django 서버 생성

소스코드 GIT : https://github.com/tkdlek11112/django_restful

시작하기 전에

지난 강의에서는 장고를 설치하고 장고 서버를 띄워봤습니다. 이번에는 python 패키지중에 하나인 restframework를 설치하고, restful api 역할을 하도록 소스를 고쳐보도록 할게요~! 역시나 자세한 설명은 유튜브 영상을 시청하시면 좋습니다. github에 소스를 올려놨기 때문에 보시면서 참고하시면 됩니다~! 강의는 2편 3편이 이 글에 대한 내용입니다~!

강의 유튜브

restframework 적용하기

장고 프레임워크 중에 djangorestframework라는 훌륭한 프레임워크가 있습니다. 간단한 설정만으로 장고를 restful api 서버로 만들어주죠. 일반적인 패키지 설치와 똑같이 pip install djangorestframework로 쉽게 설치 가능합니다. 하지만 저희는 PyCharm을 쓰기 때문에 설정 메뉴에서 간단하게 설치 가능하죠!

 

setting에서 쉽게 패키지 관리 할 수 있습니다. PyCharm 짱짱

 

패키지를 설치하고 몇 가지 설정을 해야 하는데요, 일단 공식 홈페이지가 있기 때문에 링크를 걸어드리겠습니다. ㅎㅎ

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

 

Home - Django REST framework

 

www.django-rest-framework.org

 

이 홈페이지도 튜토리얼이 상당히 잘 돼있기 때문에 영어가 조금만 되시는 분이면 읽으면서 따라 하는 게 좋아요. 일단 저는 속성으로 하겠습니다. 먼저 해야 할 건 setting.py에 몇 가지 소스를 추가하는 거예요.

#setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
]

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}

장고는 앱 단위로 관리하기 때문에 방금 설치한 rest_framework 앱을 명시해주어야 합니다. 그다음 rest_framework 권한 설정을 하기 위한 설정도 넣어줍니다. setting.py에 어떤 위치에 추가하셔도 상관없어요~!

이제 프레임워크를 사용할 준비가 끝났습니다. 유튜브에서는 공식 홈페이지에 있는 샘플 소스를 한번 실행해봤는데 블로그에는 패스하고 바로 주소록 서비스를 만들어볼게요.

일단 주소록 앱을 만듭니다. 기억하시죠? 장고는 앱 단위로 프로젝트를 관리하기 때문에 새로운 서비스가 있으면 앱을 하나 만드시는 게 좋습니다. 사실 안 만들고 하나에 욱여넣어도 되긴 하는데 그럼 관리가 힘들어져요 ㅎㅎ

앱 설치는 터미널에서 python manage.py startapp addresses를 입력하시면 됩니다.

PyCharm에 있는 터미널에서 명령어를 칩시다. 가상머신이 켜져있는거 확인 필.수!

startapp을 하면 프로젝트 폴더 안에 addresses라는 폴더가 생긴 것을 확인할 수 있습니다. 디폴트로. py파일 몇 개도 같이 생깁니다.

serializers는 제가 만든 파일입니다 

 

개발 공부하시다 보면 MVC 모델이라고 아주 귀에 못이 박히도록 듣습니다. Model, View, Controller라는 디자인 패턴인데, 데이터 모델과, 화면에 보이는 뷰, 그리고 데이터를 가공하고 처리하는 컨트롤러 영역으로 나누어서 프로그램을 설계하는 방식인데요, 장고는 쪼~끔 다릅니다. 일단 모델은 똑같은 개념입니다. 대신 장고에서의 뷰는 일반적인 MVC 모델에서 컨트롤러 역할을 합니다. 이름은 뷰인데 실제로는 데이터를 처리하는 부분이죠. 왜 그렇게 했을까요 ㅡㅡ?? 원래의 뷰는 장고에서는 템플릿입니다. html로 구성된 템플릿 영역이 MVC에서의 뷰 역할을 하죠. 그래서 다른 거하시다 장고로 넘어오시는 분들이 많이 헷갈려합니다 ㅎㅎ

이 얘기를 왜 했냐면, 디폴트로 생성되는 소스들 이름에 모델과 뷰가 있습니다. 템플릿은 보통 따로 폴더를 만들어서 관리를 하는데 여기서는 템플릿이 아직 필요가 없습니다. 왜냐면 화면을 안 만들 예정이거든요~! 클라이언트에서 요청이 오면 응답만 주면 됩니다. 이제 주소록 서비스를 만들어 볼까요?

먼저 model.py를 손봐야 합니다. 모델은 데이터 정의인데요. 쉽게 생각하면 테이블을 만드는 부분입니다. 음 주소록은 간단하게 이름이랑 전화번호, 주소까지만 저장하도록 만들어볼게요.

#models.py
from django.db import models

class Addresses(models.Model):
    name = models.CharField(max_length=10)
    phone_number = models.CharField(max_length=13)
    address = models.TextField()
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['created']

소스는 간단합니다. Addresses 객체 안에 name, phone_number, address, crested 필드가 있고, 각 필드는 models.XXXX를 이용해 데이터 타입을 정의합니다. 대부분 CharField (DB에서는 char)로 잡아주고 몇 가지 옵션을 괄호 안에 넣어서 설정할 수 있습니다. pk를 지정하지 않으면 id라는 필드가 자동으로 생기며 pk역할을 하게 됩니다. created는 auto_now_add 옵션이 있는데, 객체를 생성하는 시간을 자동으로 넣어줍니다.

이제 시리얼라이저(serializer)를 만들어야 하는데, 이건 장고 디폴트로 생성되는 .py파일이 아닙니다. restframework에서 사용하는 기능인데, 모델로 만든 데이터를 json형태로 간단하게 바꿔주는 역할을 하게 됩니다. 소스를 보시면 이해가 실 거예요~

#serializers.py
from rest_framework import serializers
from .models import Addresses


class AddressesSerializer(serializers.ModelSerializer):
    class Meta:
        model = Addresses
        fields = ['name', 'phone_number', 'address']

 

models.py보다 간단합니다. 일단 models.py에서 만든 Addresses모델을 가져옵니다. 그다음 Serializer를 만드는데, Meta에 사용할 모델이랑 사용할 필드만 적으면 끝입니다. 이제 이 Serializer는 객체 데이터를 넣으면 name, phone_number, address 필드만 json으로 바꿔서 출력해주는 역할을 하게 됩니다.

 

이제 제일 중요한 views.py를 건듭시다!

#views.py
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import Addresses
from .serializers import AddressesSerializer
from rest_framework.parsers import JSONParser
# Create your views here.


@csrf_exempt
def address_list(request):
    if request.method == 'GET':
        query_set = Addresses.objects.all()
        serializer = AddressesSerializer(query_set, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = AddressesSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)


@csrf_exempt
def address(request, pk):

    obj = Addresses.objects.get(pk=pk)

    if request.method == 'GET':
        serializer = AddressesSerializer(obj)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'PUT':
        data = JSONParser().parse(request)
        serializer = AddressesSerializer(obj, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)

    elif request.method == 'DELETE':
        obj.delete()
        return HttpResponse(status=204)


@csrf_exempt
def login(request):
    if request.method == 'POST':
        data = JSONParser().parse(request)
        search_name = data['name']
        obj = Addresses.objects.get(name=search_name)

        if data['phone_number'] == obj.phone_number:
            return HttpResponse(status=200)
        else:
            return HttpResponse(status=400)

소스가 길져?

일단 크게 보면 address_list, address, login 3개의 서비스가 있습니다. address_list는 주소록 전체를 조회하거나 신규 주소를 생성하는 역할을 하게 됩니다. 안에 if문을 통해 올라온 요청이 GET인지 POST인지 구분하기 때문에 GET이면 전체조회, POST면 신규생성역할을 하게됩니다. address는 단건 조회, 수정, 삭제 기능을 하고, 마지막으로 login은 주소록의 이름과 폰번호를 아이디, 비번으로 생각하고 로그인 기능을 구현하면 어떻게 될지 만들어보았습니다.

address_list를 먼저 보자면, GET으로 조회 시 Address.objects.all()로 모~~ 든 객체를 다 읽어옵니다. 이 읽어온 객체를 이전에 만든 시리얼 라이져 안에 넣으면 json형태로 반환됩니다. 그리고 return으로 JsonResponse를 주면 끝~! 여기서 retrun은 항상 Response형태여야 합니다. Httpresponse든 JsonResponse든 ~!
POST는 좀 복잡한데요, 일단 JSON 파서를 통해 request를 읽어오는 코드가 있는데, POST는 CREATE기능이기 때문에 만들어야 하는 객체 데이터를 담아서 올라옵니다. JSON형태로 올라오기 때문에 request에서 데이터를 뽑아오기 위해 JSON파서를 사용한 것이죠. 이렇게 파싱 한 데이터를 시리얼라이저에 넣습니다. 그럼 시리얼라이저에서 선언했던 모델, 필드와 비교해서 일치하면 (is_valid)이면 save()를 통해 객체를 만듭니다. 틀리면 에러를 내뱉고요. 

그다음 단 건조회인 address를 보면 GET, PUT, DELETE가 있는 걸 볼 수 있습니다. 각각 조회, 수정, 삭제 역할을 하게 되죠. 특징으로는 셋다 하나의 객체를 선택해서 처리하는 로직이기 때문에 공통적으로 하나를 조회하는 코드가 제일 위에에 있습니다. Address.objects.get(pk=pk) 인데여, 단건조회에는 url에 pk번호가 같이 올라와야 하기 때문에 pk로 찾습니다. url을 보시면 ~/addresses/1/ 이런 식으로 맨뒤에 숫자로 pk값이 들어갑니다. 
pk로 객체를 하나 불러온 다음 GET이면 전체 조회에서 하던 것처럼 데이터를 시리얼라이저에 넣으면 됩니다. PUT이면 수정인데, 사실 로직은 POST와 똑같습니다. 시리얼라이저에 넣고 save()하면 끝인데, 대신 넣을 때 선택된 객체도 같이 넣는다는 점만 다릅니다. 신규 생성이 아니라 수정이기 대상을 넣어야 하는 거죠. DELETE는 그냥 .delete()하면 지워집니다 ㅎㅎ

마지막으로 login인데 여긴 좀 로직이 들어갑니다. 단건조회처럼 객체를 불러오긴 하는데 pk값이 올라오는 게 아니라 입력된 아이디(여기선 이름이죠)로 찾아야 됩니다. 사실 pk=pk 부분을 name=search_name으로 바꿔준 거뿐이지만요. DB에 있는 폰번호와 입력된 폰번호를 비교해서 맞으면 성공(200) 아니면 실패(400)를 내려줍니다.

 

views.py와 urls.py연결

views에서 각 기능들을 만들면 이제 어떤 URL로 이 기능들을 불러올지 셋팅해야합니다. urls.py에서 각각의 서비스를 연결시킵니다.

#urls.py
from django.conf.urls import url, include
from addresses import views
from django.urls import path


urlpatterns = [
    path('addresses/', views.address_list),
    path('addresses/<int:pk>/', views.address),
    path('login/', views.login),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

path 함수로 URL과 views.py에서 만든 기능들을 연결시킵니다. 아까 단건조회에서는 url에 pk가 올라온다고 했는데 <int:pk> 형태로 적은걸 잘 참고해서 보시면 되겠습니다. 저렇게 하면 pk값이 address(request, pk)로 들어가 됩니다. 

이제 서버를 실행시키면 되는데, 실행하기 전에 python manage.py makemigrations, python manage.py migrate를 해줍니다. 그래야 새로 설치했던 addresses앱과 모델이 적용되기 때문이죠~!

 

DB 내용 보기

이번 프로젝트에서는 sqlite3 데이터베이스를 사용했는데요, 왼쪽에 파일 목록을 보면 db.sqlite3이라고 있는 게 보입니다. 이게 DB인데.. 어떻게 여는지 궁금하실 겁니다. 더블클릭하면 어떤 걸로 열 건지 물어보긴 하는데 딱히 마땅한 게 없거든요 ㅎㅎ 이럴 때는 외부 플러그인을 사용해야 합니다.

플러그인에서 Database Navigator 설치!

 

Database Navidator를 설치하면 DB를 볼 수 있는 window가 생깁니다.

 

DB Browser가 생겼어요
새로운 커넥션을 만들고 db경로를 아까 본 db.sqlite3을 선택하면~!
요렇게 생성된 DB들을 볼 수 있습니다. DB 콘솔에서 쿼리도 칠 수 있습니다~!

 

테스트해보기

막상 서버를 띄웠는데 API를 호출할 수 있는 클라이언트가 없습니다~! 이럴 땐 restful api 테스트 툴을 사용하면 되는데요, 여러 가지가 있는데 저는 insomnia라는 툴을 사용합니다. 툴 사용방법은 아래 링크 참조 ㅎ_ㅎ

https://cholol.tistory.com/421

 

[핵 쉬운] python, flask로 restful api 서버 만들기,

Flask(python) 사용해서 RESTful api서버 만들기 한동안 토이 프로젝트를 진행할 때, api서버는 항상 php를 이용해 만들었습니다. 예전에 안드로이드와 mysql을 php를 활용해 연동한 적이 있는데 이때 사용하던게..

cholol.tistory.com

 

POST로 데이터를 좀 만들어보고 조회를 해봅시다. POST로 데이터 생성하는 건 URL을 ~/addresses/로 하고 POST로 날리면 됩니다.

요롷게 생성합니다.

 

조희와 수정도 각각 만들어서 해보세요~!

마지막으로 LOGIN은 아래와 같이 일부러 틀린 phone_number를 넣어보고 맞는 phone_number도 넣어봅시다. 200이 오면 성공이고 400이 오면 에러입니다.

로그인이 잘 되는지 봐봐요~!

 

 

마치며

장고에 restframework를 적용하고 로그인 기능을 구현해봤습니다. 물론 실제 회원 모델로 한 게 아니지만요~! 이제 다음 강의는 클라이언트를 실제로 만들어서 고도화된 로그인 기능을 만들어볼까 합니다. 예전에 제가 쓴 안드로이드에서 로그인 기능 구현 글을 업그레이드 한 버전이 되겠죠. 이번에는 웹화면도 만들어서 안드로이드와 웹으로 만들어보겠습니다. 따라오시느라 수고하셨습니다~!

 

 

댓글(2)

  • Cheol_kk
    2020.07.14 02:32

    안녕하세요~ Youtube와 블로그 잘 보고있습니다. 덕분에 장고 공부하는데 많은 도움이 됩니다. ㅎㅎ
    혹시 API Document는 어떻게 관시하시나요?
    swagger, drf-yasg 같은 라이브러리를 사용하시는지 궁금합니다.

    • 2020.07.15 17:39 신고

      안녕하세요~

      따로 툴을 사용해서 관리하고 있지는 않는데요,

      회사에서는 보통 엑셀이나 구글 드라이브로 문서화해서 관리하거나 Confluence와 같은 wiki 툴을 사용해서 공유하고 관리합니다.

      어떤곳은 그냥 postman 툴로 테스트를 겸하면서 관리하기도 하구요~

      말씀해주신 툴은 유용하기는 한데, 유연성이 조금 떨어져서 복잡한 로직의 API를 문서화하는데 좀 힘들었던거 같아요~!

Designed by JB FACTORY