Initially, Django assumed work with only one database (a system constraint including such things as the
DATABASE_ * settings group
) . During all this time, the need to support the ability to work with several
databases was clearly felt. As part of work on version 1.2 during
Google Summer of Code, support for multiple
databases was included on the trunk. These innovations are associated with a number of internal changes, as well as several successful extensions to existing
database interfaces.
Multi- DB interface
The most noticeable change in Django is that, instead of writing database settings like this:
DATABASE_ENGINE = "postgresql_psycopg2"
DATABASE_NAME = "my_big_project"
DATABASE_USER = "mario"
DATABASE_PASSWORD = "princess_peach"
You write the following:
')
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "my_big_project",
"USER": "mario",
"PASSWORD": "princess_peach",
},
"credentials": {
"ENGINE": "django.db.backends.oracle",
"NAME": "users",
}
}
Ultimately, all projects will have to be translated into this form, although the old format will be supported in Django up to version 1.4. The only key that has a critical meaning in the
DATABASES dictionary is
“default” - “default”. If you are using a database, you need to define a
“default” database.
Now that you have told Django about all of your databases, you need to find a way to tell Django how to use them. The first interface change in this area is the
using () method.
using () takes a single parameter
database name (
database names are keys of the
DATABASES dictionary), and binds the
QuerySet to this database. Like any other tool of the
QuerySet class, it can be chained if necessary (as, for example, the
order_by () method, which updates the results of the first query upon a second query). In fact, it gives you the opportunity to fully control where the data will be read from (and when deftly using the
create () ,
delete () and
update () methods even makes it possible to control the recording):
>>> User.objects.filter (username__startswith = "admin"). Using ("credentials")
New methods for working with the
QuerySet class
delete () and
save () take an additional argument of using, to which, again, the name of the
database is passed.
In addition, a new class method
Managers ,
db_manager () , which also takes the name of the
database . Its function is essentially close to the function of the
using () method. The main difference is this: instead of returning a
QuerySet , it returns a new
Manager . The script to use it makes it possible to chain it with those methods of the class Managers that do not return a
QuerySet (for example, such as
create_user () of the class
UserManager ).
DB routers
Using all these methods, you get the opportunity to implement any system that uses multiple databases. Including
master-slave replication, partitioning and sharding. However, this will not necessarily be convenient. You will often have to use requests to the method
using () in the code, which is not best compatible with the principle of reusable Django applications (for this reason the
using option was removed from the
Meta model class). In addition, in some cases, the
QuerySet class is not fully defined. So, for example, to access the data of the
User class, the
my_obj.user method
will implicitly create a
QuerySet , but the
using () method will have no place to send the request. This was the reason for the emergence of the concept of a “
database router”. The
DB routers receive all the information about the request that you want to complete, and determine which database needs to be accessed. Routers are set in the configuration file as a list of
DATABASE_ROUTERS :
DATABASE_ROUTERS = [
"path.to.AuthRouter",
"path.to.MasterSlaveRouter",
]
DATABASE_ROUTERS is set by the list, because the router at any stage can return the value None and then Django will go to the next router from the list. Routers can define the following methods:
- db_for_read
- db_for_write
- allow_relation
- allow_syncdb
The first two methods are obvious; they return the name of the
database against which the query is being executed. The
allow_relation method
is designed to control the reasonableness of requests. Django will not allow you to create deliberately incorrect connections between
databases . That is, if you try to create a relationship between two data structures from different
databases (for
ForeignKey or for
ManyToManyField ), using this method, Django will request the necessary confirmation. And the last method
allow_syncdb allows
you to determine which of the databases will create a specific model.
The Django documentation for working
with several databases , as always, gives a lot of practical examples. Including examples that describe how to start applying common patterns with database routers. Supporting multiple databases offers tremendous advantages and greatly expands the scope of Django.