は、DB接続を表すモデルクラスを作成します。
class Database(models.Model):
name = models.CharField(max_length=256, unique=True)
config = JSONField()
が別個にDB接続エンティティをlabel
プロパティを追加します。ここでは、Djangoの設定で文字列DYNAMIC_DATABASES_PREFIX
とDYNAMIC_DATABASES_SEPARATOR
を設定する必要がありますが、また、いくつかの定数としてハードコーディングすることができます
class Database(models.Model):
...
@property
def label(self):
# We want to be able to identify the dynamic databases and apps
# So we prepend their names with a common string
prefix = getattr(settings, 'DYNAMIC_DATABASES_PREFIX', 'DYNAMIC_DATABASE')
separator = getattr(settings, 'DYNAMIC_DATABASES_SEPARATOR', '_')
return '{}{}{}'.format(prefix, separator, self.pk)
DjangoのDB接続からのDB接続を削除/にDB接続を追加するためのメソッドを追加しますまた、ジャンゴを実行しているとの接続を登録する接続名による接続のルックアップを追加
class Database(models.Model):
...
def register(self):
# label for the database connection and dummy app
label = self.label
# Do we have this database registered yet
if label not in connections._databases:
# Register the database
connections._databases[label] = self.config
# Break the cached version of the database dict so it'll find our new database
del connections.databases
# Have we registered our fake app that'll hold the models for this database
if label not in apps.app_configs:
# We create our own AppConfig class, because the Django one needs a path to the module that is the app.
# Our dummy app obviously doesn't have a path
AppConfig2 = type('AppConfig'.encode('utf8'),(AppConfig,),
{'path': '/tmp/{}'.format(label)})
app_config = AppConfig2(label, label)
# Manually register the app with the running Django instance
apps.app_configs[label] = app_config
apps.app_configs[label].models = {}
def unregister(self):
label = self.label
if label in apps.app_configs:
del apps.app_configs[label]
if label in apps.all_models:
del apps.all_models[label]
if label in connections._databases:
del connections._databases[label]
del connections.databases
: - (私たちは重複したテーブル名と異なるデータベースを持つことができ、このよう気の利いた部分は、各DB接続のためのダミーアプリを入れています)インスタンス、それをoperatにするional:
class Database(models.Model):
...
def get_model(self, table_name):
# Ensure the database connect and it's dummy app are registered
self.register()
label = self.label
model_name = table_name.lower().replace('_', '')
# Is the model already registered with the dummy app?
if model_name not in apps.all_models[label]:
# Use the "inspectdb" management command to get the structure of the table for us.
file_obj = StringIO()
Command(stdout=file_obj).handle(database=label, table_name_filter=lambda t: t == table_name)
model_definition = file_obj.getvalue()
file_obj.close()
# Make sure that we found the table and have a model definition
loc = model_definition.find('(models.Model):')
if loc != -1:
# Ensure that the Model has a primary key.
# Django doesn't support multiple column primary keys,
# So we have to add a primary key if the inspect command didn't
if model_definition.find('primary_key', loc) == -1:
loc = model_definition.find('(', loc + 14)
model_definition = '{}primary_key=True, {}'.format(model_definition[:loc + 1], model_definition[loc + 1:])
# Ensure that the model specifies what app_label it belongs to
loc = model_definition.find('db_table = \'{}\''.format(table_name))
if loc != -1:
model_definition = '{}app_label = \'{}\'\n {}'.format(model_definition[:loc], label, model_definition[loc:])
# Register the model with Django. Sad day when we use 'exec'
exec(model_definition, globals(), locals())
# Update the list of models that the app
# has to match what Django now has for this app
apps.app_configs[label].models = apps.all_models[label]
else:
logger.info('Could not find table: %s %s', label, table_name)
else:
logger.info('Already added dynamic model: %s %s', label, table_name)
# If we have the connection, app and model. Return the model class
if (label in connections._databases and label in apps.all_models and model_name in apps.all_models[label]):
return apps.get_model(label, model_name)
デシベルの選択のために述べた設定文字列を使用して、カスタムDBルーティングを作成します。
class DynamicDatabasesRouter(object):
label_prefix = '{}{}'.format(
getattr(settings, 'DYNAMIC_DATABASES_PREFIX', 'DYNAMIC_DATABASE'),
getattr(settings, 'DYNAMIC_DATABASES_SEPARATOR', '_')
)
def db_for_read(self, model, **hints):
if model._meta.app_label.startswith(self.label_prefix):
# We know that our app_label matches the database connection's name
return model._meta.app_label
return None
def db_for_write(self, model, **hints):
if model._meta.app_label.startswith(self.label_prefix):
# We know that our app_label matches the database connection's name
return model._meta.app_label
return None
def allow_relation(self, obj1, obj2, **hints):
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
return None
の設定でルータ登録:作る
DATABASE_ROUTERS = ['myapp.routing.DynamicDatabasesRouter']
(オプション)あなたがそれを使用する場合、管理サイトで変更可能なモデル:
def config(conn):
return json.dumps(conn.config)
config.short_description = 'Config'
class DatabaseAdmin(admin.ModelAdmin):
list_display = ('name', config)
admin.site.register(Database, DatabaseAdmin)
ていません[この記事](のhttp:// sligodave。com/dynamic-databases-and-models-in-django-EN.html)は、必要なものを正確に記述していますか? – hoefling
ルーティングについてはどうですか?それは[この質問]で説明されています(https://stackoverflow.com/questions/8054195/django-multi-database-routing) –
@hoeflingこれは私が必要とするexcatlyです、私はなぜ私ができなかったのか分からないそれを見つける。 あなたが書いて答えたら私はそれを正しい答えとして受け入れます。 –