서론
백엔드 초기 설정
Amazon RDS 연결
RDS에서 데이터 가져오기
병원 목록 뷰 구현
이번 글에서는 백엔드에서 필요한 초기 설정을 진행하고, Amazon RDS와 연결해서 데이터를 가져온 뒤 출력해보겠습니다.
위 사진과 같은 프로젝트 구조에서 백엔드 초기 설정을 하기 위해 poetry new projectname
명령어를 사용할 경우, 아래 사진과 같이 backend 폴더 내에 backend 폴더가 중복으로 생성됩니다. 이러한 문제를 해결하기 위해 cd backend
명령어로 backend 폴더로 이동하고, poetry init
명령어를 사용해 프로젝트를 초기화(생성)했습니다.
poetry로 프로젝트를 생성할 경우, 프로젝트의 의존성을 관리하는 역할의 poetry.lock과 pyproject.toml 파일이 생성됩니다. 의존성을 맞추기 위해 Github에 같이 커밋되어야하므로, .gitignore에 걸려있지 않은지 확인해야 합니다.
poetry add django
, poetry add djangorestframework
,poetry add django-extensions
명령어를 사용해 필요한 라이브러리를 추가하면, 아래 사진과 같이 poetry.lock의 dependencies에 이들이 추가되는 것을 확인할 수 있습니다.
이제 Django 프로젝트를 생성해보겠습니다.일반적으로 Django 프로젝트를 생성할 때 django-admin startproject projectname
명령어를 많이 사용합니다. 이 경우, projectname 폴더 안에 projectname이라는 폴더가 중복해서 생성되므로 관리하기 어려운 구조가 됩니다. 따라서 현재 위치에 프로젝트를 생성하는 django-admin startproject projectname .
명령어를 대신 사용했습니다. 저의 경우 백엔드에서 필요한 설정을 관리한다는 의미로 프로젝트 이름을 configs로 지었으며, 필요한 기능은 별도의 django app을 생성해 구현할 예정입니다.
이전 글에서 프런트엔드 초기 설정할 때와 마찬가지로, DB 연결과 관련된 민감한 정보를 외부로부터 숨기기 위해 .env 파일을 아래와 같이 작성했습니다.
SECRET_KEY=XXX
DB_ENGINE=XXX
DB_NAME=XXX
DB_USER=XXX
DB_PASSWORD=XXX
DB_HOST=XXX
DB_PORT=XXX
이제 해당 정보들을 settings.py에서 불러와서 RDS와 연결해야 하는데, 이를 위해서 django-environ이라는 라이브러리를 사용했습니다.
from pathlib import Path
import os, environ
...
# 환경변수 사용
env = environ.Env(DEBUG = (bool, False))
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
SECRET_KEY = env('SECRET_KEY')
# DB 연결
DATABASES = {
'default': {
'ENGINE': env('DB_ENGINE'),
'NAME': env('DB_NAME'),
'USER': env('DB_USER'),
'PASSWORD': env('DB_PASSWORD'),
'HOST': env('DB_HOST'),
'PORT': env('DB_PORT')
}
}
...
여기서 분명히 poetry add django-environ
명령어로 라이브러리를 설치했고, 코드도 알맞게 작성했는데 위 사진처럼 environ 모듈을 찾을 수 없다는 ModuleNotFound 에러가 발생했습니다. 다른 라이브러리는 문제 없이 불러오기 때문에 environ 라이브러리만의 문제라고 생각해 dotenv라는 라이브러리로 대체해봤음에도 동일한 문제가 발생했고, poetry의 문제라고 생각해서 PYTHONPATH도 수정해봤지만 해결되지 않았습니다.
많은 시행착오를 겪은 끝에 결론적으로 가상환경을 deactivate한 뒤 다시 실행해서 문제를 해결했습니다. 아마도 가상환경을 실행 중이지 않은 상태에서 라이브러리를 추가했기 때문에 인식하지 못해서 발생한 문제인 것 같습니다.
이후에는 MySQL DB를 사용하기 위해 poetry add mysqlclient
명령어로 라이브러리 설치를 시도했을 때, Exception: Can not find valid pkg-config name. Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env vars manually 에러가 발생했습니다. 해당 문제도 해결하기 위해 여러 시행착오를 겪었지만, 결론적으로 MySQL이 설치되어있지 않아서 인식하지 못해 발생한 문제로, brew install mysql
로 MySQL 설치 이후에 다시 시도하니 에러가 발생하지 않았습니다.
Amazon RDS(MySQL)에 이미 데이터가 다 적재된 상태이고, 이를 백엔드에서 가져오기만 하면 되는 상황이기 때문에 모델을 정의하는 것이 맞는지에 대해 고민했습니다. 그 결과, Django ORM의 쿼리, 필터링 기능을 사용할 수 있고, 데이터를 더 일관된 형태로 사용할 수 있기 때문에 모델을 정의했습니다. 향후에라도 데이터가 수정될 가능성이 있다면 migration을 진행하는 것이 맞지만, 저희 프로젝트에서는 필요하지 않을 것 같아서 일단 보류했습니다.
from django.db import models
# Create your models here.
class HospitalBasic(models.Model):
hpid = models.CharField(max_length = 10, primary_key = True)
...
class Meta:
db_table = "HOSPITAL_BASIC_INFO"
여기서 MySQL은 테이블명의 대소문자를 구분하기 때문에 db_table을 MySQL에서 사용하는 것과 동일하게 정의해야 하고, primary key를 지정하지 않을 경우 Django가 자동으로 id 필드를 생성하기 때문에 RDS의 테이블 형식과 달라질 수 있다는 것을 주의해야 합니다.
RDS도 연결되었고, 테이블에 맞는 모델도 정의했으므로 shell_plus을 사용해 모든 HospitalBasic 객체를 가져오면, 아래 사진과 같이 총 522개의 데이터를 잘 가져오는 것을 확인할 수 있습니다.
이제 RDS에서 받아온 병원 목록을 브라우저에 출력할 수 있도록 뷰를 구현해보겠습니다. 우선, Django 모델을 JSON 형태의 데이터로 변환할 수 있도록 모델에 맞는 serializer를 다음과 같이 정의했습니다.
from rest_framework import serializers
from .models import HospitalBasic, HospitalDetail
class HospitalBasicSerializer(serializers.ModelSerializer):
class Meta:
model = HospitalBasic
fields = '__all__'
그 다음, generics의 ListAPIView를 상속해 병원 목록을 보여주는 HospitalList 뷰를 정의했습니다.
from rest_framework import generics
from .models import HospitalBasic
from .serializers import HospitalBasicSerializer
class HospitalList(generics.ListAPIView):
queryset = HospitalBasic.objects.all()
serializer_class = HospitalBasicSerializer
이제 외부에서 접근할 수 있도록 아래와 같이 URL을 매핑해준 뒤 Postman을 사용해 해당 URL로 접속해보면 아래 사진과 같이 병원 목록 데이터를 JSON 형태로 잘 출력하는 것을 확인할 수 있습니다.
from django.urls import path
from .views import *
urlpatterns = [
path('hospitals/', HospitalList.as_view()),
]