본문 바로가기

Django and Mongo

Django REST API & Djongo - 1. Introduce

본 작성자는 아직 1년차도 못채운 햇병아리 코더입니다.

 

(사내에 장고를 다루는 사람이 저 혼자라서) 기술한 내용중에 틀린 내용이 있을 수도 있습니다.

 

예제랍시고 올려놓은 코드가 아주 허접할 수도 있습니다.

 

미숙한 제게 조언을 주실 수 있다면 댓글 부탁드립니다. 겸허히 배우겠습니다.

 

개발 대상 사양은 모두 아래를 공통적으로 사용합니다.

[개발 OS : Windows10]

[설치 OS : CentOS 8 with gnomeUI]

[Python: 3.8]

[Mongodb : 4.4.1]

[PostgreSQL : 12.4]

[Elasticsearch : 7.9.3]

------------------------------------------------------------------

 

(본 시리즈는 하나의 작은 Toy 프로젝트를 수행하며 진행할 예정입니다. 다만, 해당 시리즈를 모두 읽지 않아도 되도록 해당 챕터에는 해당 챕터에 해당하는 내용만을 기록하도록 합니다.)

 

Django Rest API 는 장고를 조금 배운 후에 가장 많이 그 이름을 접하게되는 서드파티 프레임워크입니다.

 

Rest API는 2000년에 처음 논문으로 개념이 등장하였고, 장고는 그보다 조금 뒤인 2005년에 처음 만들어졌습니다...

 

하지만, 오리지널 장고에는 REST API의 개념이 적용되어 있지 않고, 그를 구현한 서드파티 프레임워크를 사용하게 됩니다.

 

 

Djongo는 오픈소스로 풀려있는 몽고DB 와 장고간의 ObjectMapper 입니다. ObjectMapper가 무엇을 뜻하는지 정확히는 모르겠으나 장고의 문법을 거의 그대로 사용하여 MongoDB를 다룰 수 있게 해주는 녀석입니다.

 

 

 

 

일단, 먼저 장고부터 설치하고 시작해보죠.

 

일단 자기 나름의 방식으로  가상환경을 설치합니다.

파이참 유료버전의 경우에는 장고의 설치까지 통합해서 해준다. 편리하긴 하지만 크리티컬하지는 않고, 오히려 낭비에 가깝다. 정말 필수적인 REST Framework나 Celery는 설치되지 않고, 사이킷런이나 케라스(심지어 tensorflow는 빼두고!) 등이 자동으로 설치되는데, 콘다 환경이어서 그렇다.

기본적으로는 아나콘다를 설치하여 콘다 가상환경을 만들고 거기에 장고 라이브러리를 설치하는 것이 일반적입니다.

 

 

방법은 어찌되든 좋습니다. 단순하게 pip install Django도 충분합니다.

(2021년 3월 06일 현재 djongo는 장고 3.0.5만을 지원합니다. 만약 버전을 지정하지 않았다 하더라도 djongo 설치 중에 자동으로 언인스톨 후 3.0.5 버전으로 재설치하게 됩니다.)

 

anaconda console을 열고 다음, 아래 구문 순서대로 설치합니다.

(anaconda 와 가상환경에 대해서는 추후에 게시글을 작성하도록 하겠습니다.)

(Django, Djongo, RestFramework 순서로 설치합니다.)

 

(base) C:\your\path>conda create -n OCRandNLP
(base) C:\your\path>conda activate OCRandNLP
(OCRandNLP) C:\your\path>pip install Django==3.0.5
(OCRandNLP) C:\your\path>pip install djongo
(OCRandNLP) C:\your\path>pip install djangorestframework
(OCRandNLP) C:\your\path>pip install markdown       # Markdown support for the browsable API.
(OCRandNLP) C:\your\path>pip install django-filter  # Filtering support

여기까지 입력이 완료되었다면 이제 늘 하던대로 django-admin으로 프로젝트를 생성하면 됩니다.

 

(OCRandNLP) C:\your\path>django-admin startproject OCRandNLP
(OCRandNLP) C:\your\path\OCRandNLP>cd OCRandNLP
(OCRandNLP) C:\your\path\OCRandNLP>mkdir templates

장고를 처음 생성하면 당연히 프로젝트이름과 같은 폴더와 그 하위에 다시 같은 이름의 폴더가 생성됩니다.

늘 하던대로 settings.py를 살짝 손봐줍니다.

작성해야할 부분이 매우매우매우 많지만 일단 이정도만 하겠습니다.

 

<OCRandNLP/settings.py>

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djongo', # djongo는 굳이 안적어도 작동자체는 하는 것 같습니다.
    'rest_framework', # djangorestframework 라고 적지 않도록 주의 합시다.
    'ocrapp',  # 오늘 만들 앱의 이름입니다.
]

###########################

DATABASES = {
    'default': {
        'ENGINE': "djongo",
        'NAME': "OCRandNLP", # 몽고db의 DB 명이 들어가면 됩니다.
        'CLIENT': {
            "host": "172.30.1.41", # 해당 host는 공유기 내부망 주소입니다. 
            			  # 제 경우에는 가상머신 주소에 해당합니다.
            "port": 27017
        }
    }
}

(settings.py에 대해서는 내용이 많으므로 나중에 따로 작성하겠습니다.)

 

더보기

 

내가 아는 몇 안되는 pycharm 유료 버전의 장점. 업무 쳐내기에 급급해서 IDE는 도통 들여다볼 엄두가...

 

세팅이 끝났다면

(OCRandNLP) C:\your\path\OCRandNLP>python manage.py startapp ocrapp

위 구문으로 앱을 하나 만듭니다. 여기에서 간단한 모델-뷰를 만들겁니다.

 

 

 

<ocrapp/models.py>

from djongo import models


class PreprocessedImages(models.Model):
    image_id = models.AutoField(primary_key=True)  # 나중에 수정할 부분입니다!
    image_title = models.TextField(null=True, default="a.jpg")
    image_path = models.FilePathField(null=False, default="/home/fffcoder/ocrandnlp/images/a.jpg")
    image_context = models.TextField(null=False, default="일방통행")

    class Meta:
        db_table = "preprocessed_images"

간단하게 이미지 파일의 정보를 기록하는 테이블을 만들어보았습니다.

 

여기에 차차 살을 붙여가며 진행하도록 하되 일단은 텍스트들만 다뤄보기로 하겠습니다.

 

 

<ocrapp/serializers.py>

 

from rest_framework import serializers
from ocrapp.models import PreprocessedImages


class PreprocessedImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = PreprocessedImages
        # fields = '__all__'
        fields = ["image_title", "image_context"]
        read_only_fields = ["image_id"]

serializers.py 파일을 ocrapp 폴더에 생성합니다. 그리고 위와 같이 입력해줍니다.

 

django rest framework 의 ModelSerializer는 장고 ORM의 쿼리셋 결과를 알맞은 응답 형식으로 변환해주는 역할을 합니다.

주석 처리된 "__all__" 은 모든 필드를 지정하는 방법이고, fields 에 필드를 하나하나 적으면, 해당하는 필드만 시리얼라이즈하여 응답에 반영하겠다는 뜻입니다.

 

read_only_fields 의 경우, model 에서 read_only = True 옵션을 주거나 editable=False 옵션을 주는 것으로 대체할 수 있습니다.

 

시리얼라이저는 뷰에서 사용하게 되는데, 이때, 뷰 마다 다른 read_only_fields가 필요하다면 시리얼라이저를 복수 생성해 read_only_fields를 다르게 지정할 수도 있겠군요.

 

 

<views.py>

 

from rest_framework.viewsets import ModelViewSet
from ocrapp.serializers import PreprocessedImageSerializer
from ocrapp.models import PreprocessedImages


class PreprocessedImageViewSets(ModelViewSet):
    queryset = PreprocessedImages.objects.all()
    serializer_class = PreprocessedImageSerializer

views.py 에는 restframework 가 제공하는 ModelViewSet 클래스를 하나 만들고 거기에 쿼리셋과 serializer class를 하나 선언해둡니다.

 

여기에도 붙을 살이 많지만 일단 이대로 진행합니다.

 

 

<ocrapp/urls.py>

 

from rest_framework import routers
from django.urls import path
from ocrapp import views

router = routers.SimpleRouter()
router.register('preprocessed_image', views.PreprocessedImageViewSets)

urlpatterns = [
    # path('some_functional_view_rul', views.functional_view)
]
urlpatterns += router.urls

 

<OCRandNLP/urls.py>

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('ocr/', include('ocrapp.urls'))
]

여기까지 하면 이제 아주 간단한 REST API 가 완성됩니다.

 

 

심플라우터의 URL은  아래 가이드라인을 따라가게됩니다.

(www.django-rest-framework.org/api-guide/routers/)

위 코드를 따라서 만들어지도록 아래 API Guide는 살짝 수정되어있습니다.

ocr/preprocessed_image/ GET list {basename}-list
POST create
ocr/preprocessed_image/ GET, or as specified by `methods` argument `@action(detail=False)` decorated method {basename}-{url_name}
ocr/preprocessed_image/<int:image_id>/ GET retrieve {basename}-detail
PUT update
PATCH partial_update
DELETE destroy
ocr/preprocessed_image/<int:image_id>/{url_path}/ GET, or as specified by `methods` argument `@action(detail=True)` decorated method {basename}-{url_name}

 

SimpleRouter의 경우 5개의 HTTP METHOD를 지원합니다.

 

각 메서드별로 사용법을 간단하게 살펴보면

 

GET : http://localhost:8000/ocr/preprocessed_image/1/

: image_id 가 1인 데이터를 JSON 형식으로 돌려받습니다.

 

 

POST : http://localhost:8000/ocr/preprocessed_image/

: BODY의 내용에 따라 새로운 데이터를 생성합니다. 값이 비어있다면 default 값을 사용합니다. default 값도 없다면 null,

만약 nullable 하지 않다면, error를 돌려주므로, 세심한 주의가 필요합니다. 응답으로는 생성된 데이터를 그대로 돌려주게 됩니다.

 

PUT : http://localhost:8000/ocr/preprocessed_image/1/

: image_id 가 1인 데이터를 업데이트합니다. 모든 field의 내용이 채워져 있어야 합니다. 응답으로는 생성된 데이터를 그대로 돌려주게 됩니다.

 

 

PATCH : http://localhost:8000/ocr/preprocessed_image/1/

: image_id 가 1인 데이터를 업데이트합니다. 모든 field의 내용이 채워져 있지 않아도 작동합니다. 응답으로는 생성된 데이터를 그대로 돌려주게 됩니다.

 

 

PATCH : http://localhost:8000/ocr/preprocessed_image/1/

: image_id 가 1인 데이터를 삭제합니다. 응답으로는 '아무것도 돌려주지 않습니다.' (바디가 텅텅 비어있어서 파싱하다가 널포인터익셉션이....)

 

코드가 그리 많지 않지만, 이걸로도 충분히 기능을 하는 API 하나가 뚝딱 만들어집니다.

 

 

참고

bezkoder.com/django-mongodb-crud-rest-framework/#Django_MongoDB_CRUD_Rest_API_overview

 

MongoDB + Django Rest Framework CRUD Rest API example - BezKoder

Step by Step to build MongoDB + Django Rest Framework example - Python/Django CRUD Rest Api with MongoDB - Django 2 tutorial with MongoDB

bezkoder.com

www.django-rest-framework.org/

 

Home - Django REST framework

 

www.django-rest-framework.org

www.djongomapper.com/

 

Object Database Mapper

Djongo is a smarter approach to pymongo programming. It maps python objects to MongoDB documents. It can be used with relational SQL databases as well.

www.djongomapper.com

-------------------------

 

여기까지가 간단한 맛보기고 아직 해야할 일이 많습니다.

 

이 다음 챕터는 Field에 관한 내용입니다.

ObjectID, ImageField, Embedded Field, ArrayField 등을 queryset 과 함께 다루겠습니다.

 

이외에도 다루어야할 내용들이 많습니다!

(예를들어 아직 공부도 못해본 Django Rest Framework Mongoengine 같은 것들...)