Different databases with identical models on Django

I have the following problem:

I need a different database with the same models for each user (or set of users). I have a way to find out which database the user belongs to. The problem is that I always have to use the using method for every request I make.

For instance:

 Thing.objects.using('appropriate_database').all() 

Is there a way to avoid using using and somehow make the connection between the user and the database?

+4
source share
3 answers

We did it! Let me explain how.

We wrote custom middleware and registered it as a middleware class inside our settings.py file.

 MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'our.custom.middleware.Class', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ) 

This middleware has a process_request method that creates a thread variable ( from threading import local ) to store the corresponding database name for the current user.As each request is processed by a different thread, we know that our variable value will not be accidentally changed by another thread.

The next step was to create a Database Router and register it as such.

 DATABASE_ROUTERS = ('our.custom.database.Router',) 

Note: by default, settings.py does not have the DATABASE_ROUTERS variable. You will need to create it.

Our custom Router has the same features for db_for_read and db_for_write . The only thing these methods do is to return the database name stored in our stream variable.

What is it. Now we do not need to call using every time we need to restore or save model objects.

+1
source

Sounds like a bad design that cannot scale to me. You must duplicate the schema each time you add a user.

In the best design, USER will be used on the table with one-to-many and many-to-many relationships with the objects each user requires.

+1
source

You can create a second manager on your models:

 class MyModelManager(models.Manager): def get_query_set(self): return super(MyModelManager, self).get_query_set().using('appropriate_database') class MyModel(models.Model): # "objects" is the default manager objects_db2 = MyModelManager() field1 = models.CharField(...) class MyModel2(models.Model): objects_db2 = MyModelManager() ... 

Then use the queries MyModel.objects_db2.filter(...).order_by(...)...

0
source

Source: https://habr.com/ru/post/1494956/


All Articles