2017-10-31 13 views
2

私はdjangoが新しく、djangoで複数のデータベースを動的に使用するための最良の解決策が何かを理解しようとします。 私はdjangoがsettings.pyファイルに登録された複数のデータベースを扱うことができると知っていますが、私の場合、私のリポジトリとして機能するメインデータベース(sqlite)が1つあります。サーバの起動後にDjangoの複数の動的データベース

ユーザーは、接続情報を入力してOracleデータベースに接続することを選択できます。このデータベースからデータを収集し、それを自分のリポジトリに挿入する必要があります。ユーザーは、アプリケーションを通じて複数のOracleデータベースを登録できます。 djangoからの接続を処理するために純粋なcx_Oracleクラスを使うべきかどうか、あるいはsettings.pyにそれらを登録する必要があるのだろうかと思います。

フロントエンドの各ビューは特定のデータベースにマップされ、それらの間でコンテキストを切り替える必要があります。cx_Oracleクラスを使用すると、バックエンドの正しいクラスインスタンスにリクエストをルーティングするにはどうすればよいですか?

私のユースケースに一致するものはインターネット上で見つかりませんでした。

+0

ていません[この記事](のhttp:// sligodave。com/dynamic-databases-and-models-in-django-EN.html)は、必要なものを正確に記述していますか? – hoefling

+0

ルーティングについてはどうですか?それは[この質問]で説明されています(https://stackoverflow.com/questions/8054195/django-multi-database-routing) –

+0

@hoeflingこれは私が必要とするexcatlyです、私はなぜ私ができなかったのか分からないそれを見つける。 あなたが書いて答えたら私はそれを正しい答えとして受け入れます。 –

答えて

2

コメントで見つけたように - hereは、オンザフライでデータベースを選択してサーバーインスタンスを設定する方法を説明しているので、作成者はすべてのクレジットを取得する必要があります。基本的なアプローチを修正再表示:

  1. は、DB接続を表すモデルクラスを作成します。

    class Database(models.Model): 
        name = models.CharField(max_length=256, unique=True) 
        config = JSONField() 
    
  2. が別個にDB接続エンティティをlabelプロパティを追加します。ここでは、Djangoの設定で文字列DYNAMIC_DATABASES_PREFIXDYNAMIC_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) 
    
  3. 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 
    
  4. : - (私たちは重複したテーブル名と異なるデータベースを持つことができ、このよう気の利いた部分は、各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) 
    
  5. デシベルの選択のために述べた設定文字列を使用して、カスタム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 
    
  6. の設定でルータ登録:作る

    DATABASE_ROUTERS = ['myapp.routing.DynamicDatabasesRouter'] 
    
  7. (オプション)あなたがそれを使用する場合、管理サイトで変更可能なモデル:

    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) 
    

ビューの使用例:

class HomeView(TemplateView): 
    template_name = 'home.html' 

    def get_context_data(self): 
     context = super(HomeView, self).get_context_data() 

     # We can pick which dynamic database connection we want based on a GET parameter 
     db = Database.objects.get(pk=self.request.GET.get('env', 1)) 
     # Pass the database instance to the template so we can display it. 
     context['db'] = db 

     # Get a model class for a table in our dynamic database. 
     # Lets pretend there's a table called 'author' 
     Author = db.get_model('author') 
     authors = Author.objects.all().order_by('name') 
     # Send the author instances to the template for iterating over. 
     context['authors'] = authors 

     return context 
+0

もう1つの質問があります。私たちは次の行を持っています: apps.app_configs [label]。 models = {} モデルは常に空ですので、get_modelは常にinspect_dbを実行しようとします。モデルを正しく登録するには –

関連する問題