Django uses multiple databases, while Django uses Databases
Some projects may involve the use of multiple databases. The method is simple.
1. Set the DATABASE in settings
For example, you need to use two databases:
DATABASES = { 'default': { 'NAME': 'app_data', 'ENGINE': 'django.db.backends.postgresql', 'USER': 'postgres_user', 'PASSWORD': 's3krit' }, 'users': { 'NAME': 'user_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'priv4te' }}
In this way, two databases are identified, one alias is default and the other one is user. The database alias can be determined at will.
The default alias is special. When a Model is not selected in a route, the default database is used by default.
Of course, the default value can also be set to NULL:
DATABASES = { 'default': {}, 'users': { 'NAME': 'user_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'superS3cret' }, 'customers': { 'NAME': 'customer_data', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_cust', 'PASSWORD': 'veryPriv@ate' }}
In this way, because no default database exists, you need to select database routes for all models, including the models in the third-party libraries used.
2. Define app_label for the Model that requires database selection
class MyUser(models.Model): ... class Meta: app_label = 'users'
3. Write Database Routers
Database Router is used to determine which Database a Model uses. It mainly defines the following four methods:
db_for_read
(Model,** Hints)
Specifies which database the model uses to read data.
db_for_write
(Model,** Hints)
Specifies which database the model uses to write data.
allow_relation
(Obj1,Obj2,** Hints)
Determine whether an association can be established between obj1 and obj2. It is mainly used for the foreign key and counter to counter operations.
allow_migrate
(Db,App_label,Model_name = None,** Hints)
Determine whether the migrate operation can be run on a database with the alias db.
A complete example:
Database settings:
DATABASES = { 'default': {}, 'auth_db': { 'NAME': 'auth_db', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'swordfish', }, 'primary': { 'NAME': 'primary', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'spam', }, 'replica1': { 'NAME': 'replica1', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'eggs', }, 'replica2': { 'NAME': 'replica2', 'ENGINE': 'django.db.backends.mysql', 'USER': 'mysql_user', 'PASSWORD': 'bacon', },}
If you want to achieve the following results:
The Model with the app_label as auth is read and written in auth_db, the rest of the Model is written in primary, and the read is randomly completed in replica1 and replica2.
Auth:
class AuthRouter(object): """ A router to control all database operations on models in the auth application. """ def db_for_read(self, model, **hints): """ Attempts to read auth models go to auth_db. """ if model._meta.app_label == 'auth': return 'auth_db' return None def db_for_write(self, model, **hints): """ Attempts to write auth models go to auth_db. """ if model._meta.app_label == 'auth': return 'auth_db' return None def allow_relation(self, obj1, obj2, **hints): """ Allow relations if a model in the auth app is involved. """ if obj1._meta.app_label == 'auth' or \ obj2._meta.app_label == 'auth': return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): """ Make sure the auth app only appears in the 'auth_db' database. """ if app_label == 'auth': return db == 'auth_db' return None
In this way, the Model with the app_label as auth can be read and written in auth_db and can be associated. migrate can only be run in the auth_db database.
Others:
import randomclass PrimaryReplicaRouter(object): def db_for_read(self, model, **hints): """ Reads go to a randomly-chosen replica. """ return random.choice(['replica1', 'replica2']) def db_for_write(self, model, **hints): """ Writes always go to primary. """ return 'primary' def allow_relation(self, obj1, obj2, **hints): """ Relations between objects are allowed if both objects are in the primary/replica pool. """ db_list = ('primary', 'replica1', 'replica2') if obj1._state.db in db_list and obj2._state.db in db_list: return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): """ All non-auth models end up in this pool. """ return True
In this way, the read is completed randomly in replica1 and replica2, And the write uses primary.
Finally, set in settings:
DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']
You can.
During the migrate operation:
$ ./manage.py migrate$ ./manage.py migrate --database=users
By default, the migrate operation operates the default database. to operate other databases, you can use the -- database option, followed by the database alias.
Corresponding to this, the dbshell, dumpdata, and loaddata commands all have the -- database option.
You can also manually select a route:
Query:
>>> # This will run on the 'default' database.>>> Author.objects.all()>>> # So will this.>>> Author.objects.using('default').all()>>> # This will run on the 'other' database.>>> Author.objects.using('other').all()
Save:
>>> my_object.save(using='legacy_users')
Mobile:
>>> p = Person(name='Fred')>>> p.save(using='first') # (statement 1)>>> p.save(using='second') # (statement 2)
The above code may cause problems. When p is saved in the first database for the first time, a primary key is generated by default. In this way, when the second database is used for storage, p already has a primary key, this primary key will not cause problems if it is not used, but if it is used previously, it will overwrite the original data.
There are two solutions;
1. Clear the primary key before saving:
>>> p = Person(name='Fred')>>> p.save(using='first')>>> p.pk = None # Clear the primary key.>>> p.save(using='second') # Write a completely new object.
2. Use force_insert
>>> p = Person(name='Fred')>>> p.save(using='first')>>> p.save(using='second', force_insert=True)
Delete:
From which database to delete objects
>>> u = User.objects.using('legacy_users').get(username='fred')>>> u.delete() # will delete from the `legacy_users` database
To transfer an object from the legacy_users database to the new_users database:
>>> user_obj.save(using='new_users')>>> user_obj.delete(using='legacy_users')