投稿にあたって
- 自分用のメモでもあります。
- Djangoでは単一APPにたいして一つのDBを使用する記事は多く散見しましたが、同じAPPで複数DBを使用する場合の記事が少なかったので備忘録として残します。
- またrest_frameworkを使用した記事となるため主にvalidationでの複数DB使用がメインになります。
目標
- rest_frameworkのviewsで複数のDBを参照できる
- rest_frameworkのviewsで複数のDBを更新できる
前提
- settings.pyに
default
及び その他DBがあることを前提とします。 - 下記例です。
DATABASES = {
'default': {
'ENGINE': 'your_engine',
'NAME': 'database1',
'USER': 'your_user',
'PASSWORD': 'your_passwd',
'HOST': '127.0.0.1', # your_host
'PORT': '5432', # your_port
},
'database2': {
'ENGINE': 'your_engine',
'NAME': 'database2',
'USER': 'your_user',
'PASSWORD': 'your_passwd',
'HOST': '127.0.0.1', # your_host
'PORT': '5432', # your_port
},
}
実際にコードを書いていきましょう
models
モデルはデータベースの制限を受けません。
というか、データベースの設定が出来ません。悲しい。
なのでデータベースの垣根なく書きます。
from django.db import models
# 例えばこっちがdatabase1
class DatabaseOne(models.Model):
id = models.Integer(primary_key = True)
column_one = models.CharField(max_length = 16)
# こっちはdatabase2
class DatabaseTwo(models.Model):
id= models.Integer(primary_key = True)
column_two = models.CharField(max_length = 32)
# 外部キーを持ったdatabase2
class DatabaseTwoChild(models.Model):
db2 = models.OneToOneField(DatabaseTwo, on_delete = models.CASCADE, primary_key = True)
child_column = models.CharField(max_length = 16)
参照
これは簡単ですね。
serializer等の設定も不要なため、単純にdb_managerを間に設定するだけで出来ちゃいます。
まぁ簡単!
views
from rest_framework.response import Response
from rest_framework import viewsets
from .models import DatabaseOne, DatabaseTwo
class TestViewSet(viewsets.ModelViewSet):
queryset = ''
http_method_names = ["get"] # これでGETしかできないようになります
def list(self, request):
db1 = DatabaseOne.objects.all() #ここまでは普通のqueryset
db2 = DatabaseTwo.objects.db_manager("database2").all() # default以外のDB
return Response({"result": "オッケー!"})
更新・作成
こちらは少し癖があります。
まずChildを更新しようと思うと親がdefaultではないので、serializerに少し手を加えないと、defaultのデータベースを見に行こうとしてquerysetがエラーを吐きます。
serializer
from rest_framework import serializers
from .models import DatabaseOne, DatabaseTwo, DatabaseTwoChild
from rest_framework.validators import UniqueValidator # これは外部キーを使用している場合に使用します
class DatabaseTwoChildSerializer(serializers.ModelSerializer):
class Meta:
model = DatabaseTwoChild
fields = "__all__"
db2 = serializers.PrimaryKeyRelatedField(
queryset = Database2.objects.using("database2").all(),
validators = [UniqueValidator(queryset = DatabaseTwoChild.objects.using("database2").all())]
)
def create(self, data):
save_data = DatabaseTwoChild(**data)
save_data.save(using="database2")
return save_data
これで下準備OKです!
ではviewしていきましょう
views
from rest_framework.response import Response
from rest_framework import viewsets
from .serializerimport import DatabaseTwoChildSerializer
from .models import DatabaseOne, DatabaseTwo
class TestViewSet(viewsets.ModelViewSet):
queryset = ''
http_method_names = ["post"] # これでPOSTしかできないようになります
def create(self, request):
serializer = DatabaseTwoSerializer(data = {
"child_column": "hogehoge",
})
if serializer.is_valid():
serializer.save()
else:
return Response({"result": "エラーだよ!"})
return Response({"result": "おっけー!"})
これでdefaultでないDBも更新できます。
ユーザー情報と他の情報とかでデータベースを分けたい場合に便利です。
またserializerの機能をしっかり使ってあげることで、型のチェックがキッチリできるので、ぜひ使ってみてください。