【Django】同じappで複数のDBを使用する方法

# 投稿にあたって
* 自分用のメモでもあります。
* Djangoでは単一APPにたいして一つのDBを使用する記事は多く散見しましたが、同じAPPで複数DBを使用する場合の記事が少なかったので備忘録として残します。
* またrest_frameworkを使用した記事となるため主にvalidationでの複数DB使用がメインになります。

# 目標
* rest_frameworkのviewsで複数のDBを参照できる
* rest_frameworkのviewsで複数のDBを更新できる

# 前提
* settings.pyに `default` 及び その他DBがあることを前提とします。
* 下記例です。

```python

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
モデルはデータベースの制限を受けません。
というか、データベースの設定が出来ません。悲しい。
なのでデータベースの垣根なく書きます。

```python
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

```python
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
```python
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
```python
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の機能をしっかり使ってあげることで、型のチェックがキッチリできるので、ぜひ使ってみてください。