본문 바로가기

web/Django

[django] 데이터베이스 여러개 사용하기 (django multi db)

 

기존 MSA 형태로 구축되어 API를 호출하던 방식을 직접 디비에 붙어서 수행하는 형식으로 바꾸기 위해 django에서 두개 이상의 디비를 바라보도록 하는 과정에서 글을 씁니다. (..왜  MSA에서 모놀리스로 가냐고 물으신다면.... 한시간에 1만개의 내부 API 콜을 견뎌야 하는데....돈이 없습니다. ㅜㅡㅜ)

 

1. settings에 디비 정보 추가 

settings에 기존 디비 설정이 있는 DATABASES에 추가로 이용할 디비의 정보를 넣어줍니다.

저의 경우 predict라는 이름으로 추가정보를 넣었습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('POSTGRES_DB'),
        'USER': os.getenv('POSTGRES_USER'),
        'PASSWORD': os.getenv('POSTGRES_PASSWORD'),
        'HOST': os.getenv('POSTGRES_HOST'),
    },
    'predict': {
        'ENGINE': 'django.db.backends.postgresql',
       'NAME': '데이터베이스_네임',
       'USER': 'username',
       'PASSWORD': 'password',
       'HOST': 'host.XXXXX.XXXXXX',
    }
}
cs

 

2. router.py

이제 django에서 어떤 디비를 바라볼 것인지를 위한 router.py를 만들어줍니다. 저는 기존 settings.py 가 있는 기본 app 폴더에 위치하였습니다. (위치는 어느곳이든 상관없습니다. 아래에 settings에 경로만 잘 설정해주시면 됩니다. )

 

상세한 정보는  https://docs.djangoproject.com/ko/3.0/topics/db/multi-db/#using-routers 를 보시면 됩니다 .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# -*- coding: utf-8 -*-
class Router:
    """ A router to control all database operations on models in the auth application. """
    def db_for_read(self, model, **hints):
        """ Attempts to read auth models go to auth_db. """
        if model._meta.app_label == 'predict':
            return 'predict'
        return None
 
    def db_for_write(self, model, **hints):
        """ Attempts to write auth models go to auth_db. """
        if model._meta.app_label == 'predict':
            return 'predict'
        return None
 
    def allow_relation(self, obj1, obj2, **hints):
        """ Allow relations if a model in the auth app is involved. """
        if obj1._meta.app_label == 'predict' or \
            obj2._meta.app_label == 'predict':
            return True
        return None
 
    def allow_migrate(self, db, app_label, model_name=None**hints):
        """ Make sure the auth app only appears in the 'auth_db' database. """
        if app_label == 'predict':
            return db == 'predict'
        return None
 
cs

 

위의 정보에서 predict 부분을 settings에서 설정한 디비 이름으로 변경해주셔서 사용하시면 됩니다. 

위는 어떤 디비를 어떤 별칭으로 바라볼 것인가, 마이그레이션 할때 어떤 별칭을 줄 것인가가 설정됩니다.

 

3.  settings.py에 router.py 경로 추가

settings.py 에 아래와 같은 내용을 추가 한다.

XXXXX는 router.py가 있는 앱이름이 됩니다. (혹은 기본 프로젝트 이름)

DATABASE_ROUTERS = ['XXXXX.router.Router']

 

4. app 생성과 model 가져오기 

database 연결후 ORM을 사용하기 위해 app 생성 및 스키마를 등록합니다.

django-admin startapp predictApp # <-(사용할 app 이름)

다음 명령어를 통해 기존 DB의 스키마를 django의 ORM 형식으로 가져옵니다. 

# python3 manage.py inspectdb --database=디비명 > APP이름/models.py
python3 manage.py inspectdb --database=predict > predcitApp/models.py

앞의 inspectdb-database=predict <- 이부분은 이전 단계의 settings.py databases에 등록한 key 값입니다.

뒤의 predict/models.py 의 predict 는 위에서 생성한 app 이름이며 경로가 됩니다. 

실행하면 데이터베이스의 테이블들이 models.py에 선언됩니다. 

 

특정 테이블만 가져오고 싶다면 아래와 같이 하면 됩니다.

# python3 manage.py inspectdb --database=디비명 테이블명1 테이블명2 > APP이름/models.py
python3 manage.py inspectdb --database=predict test1  test2 > predcitApp/models.py

 

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ComponentsIrradiancesensor(models.Model):
    index = models.IntegerField()
    created = models.DateTimeField()
 
    class Meta:
        managed = False
        db_table = 'components_irradiancesensor'
        
 
class ComponentsModule(models.Model):
    index = models.IntegerField()
    created = models.DateTimeField()
 
    class Meta:
        managed = False
        db_table = 'components_module'
cs

 

5. Model.py 수정

이 부분은 모델 스키마에 따라 달라집니다.

 

만일 모델에 FK / ManyToMany / OneToMany 등읜 연관관계가 있는 필드는 오류가 나게 됩니다. 

4번에서 가져온 스키마의 정보는 기존 ORM을  그대로 가져 오는것이 아닌 APP이름 + 테이블 명으로 바뀌게 되기 때문입니다. 

그래서 해당 연관 관계의 모든 필드에  related_name이 없다면 정의하셔야 합니다. 

 

두번째는 기존의 로직을 그대로 가져왔다면 ( 쿼리 포함 ) 테이블 명이 바뀜으로써 연관관계가 틀어졌다고 했는데요, 이 결과 쿼리상의 **__set으로 선언했던 inner join의 형식을 모두 바꿔줘야 합니다. 네... 쿼리를 전부 하나하나 새롭게 변경해야 합니다. 

 

Parents <- Childern 의 모델이 house 라는 APP에 등록 되어 있었다면 

기존 Parent.objects.childern__set.all()  으로 참조 가능했던 쿼리는 

APPParent.objects.APPChildern__set.all() 으로 이름이 바뀐것이죠. (APP 이름이 테이블에 붙어서...)

 

네. 테이블을 참조한 모든 곳을 전부 확인해 보셔야 합니다. (그래도 쿼리를 크게 바꾸진 않으니...나름의 위한을..)

 

 

https://docs.djangoproject.com/ko/3.0/topics/db/multi-db/

 

Multiple databases | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

 

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

django query 기초2  (0) 2020.02.18
django query 기초1  (0) 2020.02.16
django cross domain allow middleware  (0) 2019.08.16
django migrate 칼럼이 생성 안될때 ( 꼬였을때)  (0) 2019.08.09
EFK docker + django logger 커스텀  (0) 2019.07.21