본문 바로가기

Django

DB에 csv로 초기 데이터 넣기

장고 프로젝트의 settings.py에 들어가는 데이터베이스 정보는 자신의 로컬 DB에 대한 정보이다. AWS에 DB서버를 올려두고 쓰는 환경이 아닌 이상 팀원들이 가지고 있는 DB는 다 다른 것이고, 안에 들어있는 정보도 다르다. 로직을 테스트하기 위해서라면 방드시 같은 정보일 필요는 없지만, 텅 빈 DB에 새로 데이터를 손수 채워넣는 건 매우 귀찮다. 특히 레퍼런스 테이블이 존재하거나 이리저리 fk가 얽혀있는 모델에 데이터를 넣으려면 어디에 무얼 먼저 넣어야 되는지 신경쓸 게 많다.

csv파일로 미리 만들어 둔 데이터를 공유하고 이를 각자 DB에 넣으면 이런 불편이 상당부분 해소된다. 한 사람의 DB에 데이터를 쳐넣고 이를 백업 떠서 sqldump 파일을 공유하는 방법도 있겠지만, 처음 데이터를 넣는 게 고행이고 추후 모델 수정사항이 생길 경우 데이터 파일을 수정하기가 csv 파일보다는 조금 어렵다. 그래서 table별 csv 파일을 만들고 이를 DB에 넣는 py 파일을 만들었다.

 

경로

manage.py가 있는 최상위 디렉토리에 initial_data라는 폴더를 만들었다.

그 안에 모델의 column들을 맨 윗 행으로 하고 이에 맞춰 데이터를 넣은 csv 파일들을 만들었다.

 

DB에 넣는 기능을 함수화해놓고 이를 실행하는 import_data.py 파일을 작성했다.

import csv, os, sys, django

BASE_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
sys.path.append(BASE_DIR)

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
django.setup()

import_data.py 파일이 들어있는 폴더 바깥이 상위 폴더니까 그렇게 BASE_DIR을 선언했다. 세팅 셋업 코드는 장고 내 다른 걸 import해오는 코드보다 상단에 써야 된다. 이 아래에는 views.py에서 모델 class를 import하듯이 했다.

 

세팅 셋업 코드를 작성할 때 오타에 주의하자.

처음에는 BASE_DIR 설정만 하고 파일을 실행했더니 위와 같이 ImproperlyConfigured: Requested setting INSTALLED_APPS 로 시작하고 DJANGO_SETTINGS_MODULE을 정의하라는 내용의 에러가 났다. 그래서 django setting module 설정을 했는데, 그 다음엔 ImproperlyConfigured: Requested setting LOGGING_CONFIG (중략) DJANGO_SETTINGS_MODULE을 정의하라는 에러가 났다. 한참을 찾다 오타 낸 걸 알았다. setdefault 안에 DJANGO_SETTING_MODULE이라고 썼다.. S를 빼먹은 것.

 

그 다음에는

1. csv 파일을 불러와 열고

2. 그 안에 있는 데이터를 읽어

3. DB에 넣어야 된다.

 

1. csv 파일 불러와 열기

CSV_PATH    = 'initial_data/'

with open(CSV_PATH + 'admin_levels.csv', 'r') as csvfile:

경로를 주의해야 된다. import_data.py 파일은 initial_data 폴더 안에 있지만 실행은 최상위 디렉토리에서 할 예정이기 때문에 경로를 이에 맞춰 설정하고자 CSV_PATH를 선언했다. 실행시 initial_data 폴더 안에 들어가서 돌릴 거라면 csv파일이 실행 위치와 같은 경로에 있기 때문에 이렇게 CSV_PATH를 설정해줄 필요가 없다.

 

2. 그 안에 있는 데이터 읽기

이 때 파이썬 내장 함수인 csv만 쓸 수도 있고 pandas를 설치해 사용할 수도 있는데, 전자를 선택했다. csv 첫 행에 넣은 column명을 key로 사용해서 값을 가져오고 싶었기 때문에 DictReader를 사용했다.

    for row in csv.DictReader(csvfile):

 

3. DB에 넣기

읽은 csv 파일에 해당하는 장고 모델 class를 사용하여 데이터를 생성한다. 1~3의 코드를 합치면 아래와 같다.

CSV_PATH    = 'initial_data/'

with open(CSV_PATH + 'admin_levels.csv', 'r') as csvfile:
    for row in csv.DictReader(csvfile):
        AdminLevel.objects.create(name=row['name'])

 

이런 코드를 모든 csv의 column과 데이터 상태에 맞추어 작성하면 된다. 이런 코드 꾸러미를 인지하기 쉬운 단위로 묶어서 함수화했다.

샘플 문자열을 랜덤으로 잘라 넣고 싶은 데에는 ramdom.randint를 사용해 슬라이싱했다. csv를 만들다 지쳐서 양만 불리고 싶을 때는 반복문을 돌렸다. 다만 이 때는 좀 조심할 게, 파일을 여는 코드를 반복문 안으로 넣어 실행할 때마다 파일을 열어 읽어야 된다. 처음엔 파일 읽기를 일반적인 배열과 같이 생각해서 반복문 바깥에 두었는데, EOF 에러는 나지 않았지만 csv 파일에 있는 분량 만큼만 DB에 들어갔다. 마치 카세트 테이프 같은 거라고 납득했다.

 

그리고 이렇게 만들어둔 csv 파일과 업로더 파일은 공개 github repo에 올리지 않는다. 백엔드 시스템에서 사용하는 코드가 아니라 DB를 관리하기 위한 코드이고, 데이터는 보안상의 이유로 오픈하지 않는다. 그래서 1차 프로젝트 동안은 구글 드라이브를 통해 이 파일들을 공유했다.