How to work with multiple databases in Django [using Database Routers] - python

I need to isolate django`s default (auth, contenttypes, sessions) apps database, I read in documentation [Multiple Databses][1] all is clear and well explained, but not working to me :(
settings.py
DATABASES = {
'default_django': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'OPTIONS': {
'options': '-c search_path=eos,public'
},
'NAME': '****',
'USER': '*****',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '5432',
}
}
DATABASE_ROUTES = ['core.dbrouter.AuthRoute', 'core.dbrouter.GisRoute']
and ./core/dbrouter.py
class AuthRouter:
"""
A router to control all database operations on models in the
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
"""
route_app_labels = {
'auth', 'admin', 'contenttypes',
'sessions', 'messages', 'staticfiles'
}
def db_for_read(self, model, **hints):
"""
Attempts to read auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return 'default_django'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return 'default_django'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth or contenttypes apps is
involved.
"""
if (
obj1._meta.app_label in self.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the auth and contenttypes apps only appear in the
'auth_db' database.
"""
if app_label in self.route_app_labels:
return db == 'default_django'
return None
When I do python3 manage.py migrate it is shows
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
No migrations to apply.
Please, could someone explain?(Why?)
[1]: https://docs.djangoproject.com/en/3.1/topics/db/multi-db/

you forgot an R.
DATABASE_ROUTES = ['core.dbrouter.AuthRoute', 'core.dbrouter.GisRoute']
↓
DATABASE_ROUTERS = ['core.dbrouter.AuthRoute', 'core.dbrouter.GisRoute']

Related

How to migrate multiple databases in Django?

I am doing a project with Django, there are too much data so that I need to form different databases to store them. I made a database router for each app to match the unique database, but when I migrate them, all of the tables were migrate to the same database, here are the codes:
from django.conf import settings
DATABASE_MAPPING = settings.DATABASES_APPS_MAPPING
class DatebaseAppsRouter(object):
"""
该类为连接不同数据库的路由,在setting中通过设置DATABASE_MAPPING来匹配数据库
例:
DATABASE_APPS_MAAPING = {"app1":"db1", "app2":"db2"}
"""
def db_for_read(self, model, **kwargs):
"""将所有读操作指向指定的数据库"""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def db_for_write(self, model, **kwargs):
"""将所有写操作指向指定的数据库"""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def allow_relation(self, obj1, obj2, **kwargs):
"""允许使用相同数据库的应用程序之间的任何关系"""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
else:
return None
def allow_syncdb(self, db, model):
"""确保这些应用程序只出现在相关的数据库中"""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(model._meta.app_label) == db
elif model._meta.app_label in DATABASE_MAPPING:
return False
return None
def allow_migrate(self, db, app_label, model=None, **kwargs):
"""确保身份验证应用程序只出现在login数据库中"""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(app_label) == db
elif app_label in DATABASE_MAPPING:
return False
return None
By using the router, I would like to migrate multiple databases, but it doesn't work
System check identified some issues:
WARNINGS:
?: (urls.W001) Your URL pattern '^login/$' uses include with a route ending with a '$'. Remove the dollar from the route to avoid problems including URLs.
?: (urls.W001) Your URL pattern '^main/$' uses include with a route ending with a '$'. Remove the dollar from the route to avoid problems including URLs.
?: (urls.W005) URL namespace 'admin' isn't unique. You may not be able to reverse all URLs in this namespace
Operations to perform:
Apply all migrations: Themepark, admin, auth, contenttypes, ginseng_holding_hotel, holiday_resort, login, nature_scenic_area, sessions, the_scent_spot_trusteeship, tourist_communications, travel_agency
Running migrations:
No migrations to apply.
So how to solve this problem? Thanks!
Replace your app name with 'your_app' and the database you want to run the migration on with 'your_app_respective_db' from the mapping you have. Hope this helps.
python manage.py migrate your_app --database your_app_respective_db
I think the problem is with your urls.py
If you are using django.urls.path() you don't have to add the carrot sign and the dollar sign and do it this way.
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login, name='login'),
path('main/', views.main, name='main'),
]
But if you were using django.urls.url() then you should do this
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login, name='login'),
url(r'^main/', views.main, name='main'),
]
if you don't mind, can you show us your urls.py?
You have to add your different DB details as per your app in settings.py as following:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': config('DATABASE_NAME'),
'USER': config('DATABASE_USER'),
'PASSWORD': config('DATABASE_PASSWORD'),
'HOST': config('DATABASE_HOST'),
'PORT': config('DATABASE_PORT'),
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
},
'app1_name': {
'ENGINE': 'django.db.backends.mysql',
'NAME': config('APP1_DATABASE_NAME'),
'USER': config('DATABASE_USER'),
'PASSWORD': config('DATABASE_PASSWORD'),
'HOST': config('DATABASE_HOST'),
'PORT': config('DATABASE_PORT'),
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
},
'app2_name': {
'ENGINE': 'django.db.backends.mysql',
'NAME': config('APP2_DATABASE_NAME'),
'USER': config('DATABASE_USER'),
'PASSWORD': config('DATABASE_PASSWORD'),
'HOST': config('DATABASE_HOST'),
'PORT': config('DATABASE_PORT'),
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
}
}
default will be your main app. Also when you do migrations and migrate, you need to mention the database name like following.
python manage.py makemigrations app1
python manage.py migrate app1 --database=app1

Serving separate database per user django

i am creating database according this now: Saperate PostgreSQL db for each client, with automated migrations on creating client on single Django app and on same server
Now I want to serve the db per user. We can return db from db routers only if they exists in the DATABASES varriable in the settings file.
Does anybody know how to serve db which are created on server but not added in settings.py, which will be according to the logged in user.
There will be a main db for user, in which their relations with their db name is saved.
Settings.py
DATABASE_ROUTERS = ['app.router_middleware.DataBaseRouter']
DATABASES = {'default':
{
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'abc',
'USER': 'xyz',
'PASSWORD': '*****',
'HOST': 'localhost',
'PORT': '5432',
}
}
import django
django.setup()
from Client.views import ALL_DB
DATABASES.update(ALL_DB)
Client.views
ALL_DB = { x.db_name: {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': x.db_name,
'USER': 'xyz',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '5432',
} for x in Client.objects.all()}
router_middleware.py
db_name = 'default'
class RouterMiddleware(CoreSessionMiddleware):
def process_request(self, request):
if request.user.is_authenticated() :
user = request.user
if ClientEmployee.objects.filter(user=user).exists():
client_employee = ClientEmployee.objects.get(user=user)
db_name = client_employee.client.db_name
class DataBaseRouter(object):
def db_for_read(self, model, **hints):
return db_name
def db_for_write(self, model, **hints):
return db_name

Django saving models in different databases

I am new to Django.
I have two apps created in my project:
python3 manage.py startapp app1
python3 manage.py startapp app1
I am using Mysql as DB and I want that each app should use different schemas.
I try to follow the steps described here:
Sharing (mysql) database between apps Django with Database routers
So in settings.py I defined 2 MySql schemas and keep default schema and
add the add the DATABASE_ROUTERS.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app1',
'app2',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'mydb1':{
'ENGINE': 'django.db.backends.mysql',
'NAME': 'APP1DB',
'USER': 'user1',
'PASSWORD': '****',
'HOST': 'localhost', # Or an IP Address that your DB is hosted on
'PORT': '3306',
},
'mydb2':{
'ENGINE': 'django.db.backends.mysql',
'NAME': 'APP2DB',
'USER': 'user1',
'PASSWORD': '****',
'HOST': 'localhost', # Or an IP Address that your DB is hosted on
'PORT': '3306',
},
}
DATABASE_ROUTERS = ['app1.dbRouter.App1DBRouter', 'app2.dbRouter.App2DBRouter']
Additional files:
app1/models1.py
from django.db import models
# Create your models here.
class Model1(models.Model):
name = models.CharField(max_length=100)
app2/models2.py
from django.db import models
# Create your models here.
class Model2(models.Model):
name = models.CharField(max_length=100)
And files:
app1/dbRouter.py
class App1DBRouter(object):
def db_for_read(self,model, **hints):
if model._meta.app_label == 'app1':
return 'mydb1'
return None
def db_for_write(self,model, **hints):
if model._meta.app_label == 'app1':
return 'mydb1'
return None
def allow_relation(self,obj1, obj2, **hints):
if obj1._meta.app_label == 'app1' and \
obj2._meta.app_label == 'app1':
return True
return None
def allow_syncdb(self,db, model):
if db == 'mydb1':
if model._meta.app_label == 'app1':
return True
elif model._meta.app_label == 'app1':
return False
return None
app2/dbRouter.py:
class App2DBRouter(object):
def db_for_read(self,model, **hints):
if model._meta.app_label == 'app2':
return 'mydb2'
return None
def db_for_write(self,model, **hints):
if model._meta.app_label == 'app2':
return 'mydb2'
return None
def allow_relation(self,obj1, obj2, **hints):
if obj1._meta.app_label == 'app2' and \
obj2._meta.app_label == 'app2':
return True
return None
def allow_syncdb(self,db, model):
if db == 'mydb2':
if model._meta.app_label == 'app2':
return True
elif model._meta.app_label == 'app2':
return False
return None
After this I expect that when I run commands makemigrations and migrate I would get 2 different tables in 2 different schemas?
So:
$ python3 manage.py makemigrations
Migrations for 'app1':
app1/migrations/0001_initial.py
- Create model Model1
Migrations for 'app2':
app2/migrations/0001_initial.py
- Create model Model2
$ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, app1, app2, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
...
Applying sessions.0001_initial... OK
But there are no tables created except django_migrations in both schemas.
If I use command:
$ python3 manage.py migrate --database=mydb1
then both model tables are created in the APP1DB.
mysql> SHOW TABLES;
+----------------------------+
| Tables_in_APP1DB |
+----------------------------+
| app1_model1 |
| app2_model2 |
| auth_group |
So how to solve this?
According to the documentation database routers may implement the method allow_migrate(db, app_label, model_name=None, **hints) in order to determine whether a certain migration should be performed or not. The methods of custom database routers are always invoked through the default database router django.db.router:
def allow_migrate(self, db, app_label, **hints):
for router in self.routers:
try:
method = router.allow_migrate
except AttributeError:
# If the router doesn't have a method, skip to the next one.
continue
[...]
return True
Because your routers don't define such a method it simply returns True at the end of the method and therefore applies the requested migration to the specified database.
You can achieve the separation of apps across the different databases by defining this method:
class App1DBRouter(object):
[...]
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'app1':
return db == 'mydb1'
return None
And similarly for app2.

Simple step-by-step guide to Django multiple databases please

I've been through a few posts and the Django documentation but still can't get multiple databases to work. I'm new to Django and feel quite confused indeed.
In my project, one app should use an existing vo.sqlite3 with lots of data in it. I want to be able to handle this vo.sqlite3 in my vo app, separately from the default database db.sqlite3 (the one that handles users, etc).
Would you anyone be able to point me to a simple step-by-step way to get such setup to work?
Many thanks.
An example, in your settings, set up your databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite1'),
},
'client1': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite2'),
},
}
Then wharever you perform a query, you can select the database.
UserModel.objects.using(db).get(username=username)
db = you database name
You can view the full example here
Not only levi's solution above worked, I even managed to make automated routing work, see my settings.py and routers.py.
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'db.sqlite3',
},
'vodb': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'vo.sqlite3',
}
}
DATABASE_ROUTERS = ['vo.routers.vo_Router',]
DATABASE_APPS_MAPPING = {'vo': 'vodb'}
routers.py
from django.conf import settings
class vo_Router(object):
def db_for_read(self, model, **hints):
return 'vodb'
def db_for_write(self, model, **hints):
return 'vodb'
def allow_relation(self, obj1, obj2, **hints):
db_list = ('default', 'vodb')
if obj1._state.db in db_list and obj2._state.db in db_list:
return True
return None
def allow_migrate(self, db, model):
return True
def allow_syncdb(self, db, model):
if db == 'vodb':
return model._meta.app_label == 'vo'
elif model._meta.app_label == 'vo':
return False
return None
The piece that was missing was the execution of manage.py syncdb --database=vodb. However, this added a lot of unnecessary Django tables to the app database vo.sqlite3, and even created a new table for the object defined in my models.py.
In my case, I wanted just to link existing tables (with data) in vo.sqlite3 to the objects in models.py. Is there a way to do it Django? Thanks.

Different databases for different apps in Django [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have multiple apps in my Django site: mainsite, blog and tutorials.
Can I use different databases (e.g. PostgreSQL, MySQL) in different Django apps?
Here is what you will have to do to get going.
Update settings for databases that you want to use.
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/var/db/projectdb'
}
'db_app1': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/var/db/app1db'
}
'db_app2': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/var/db/app2db'
}
For each database, implement a database router that will route the queries appropriately. In your case implement in each app. Note this more or less taken from django docs.
dbRouter.py (place in 'app1' folder):
# DB router for app1
class App1DBRouter(object):
"""
A router to control db operations
"""
route_app_labels = {'app1'}
db_name = 'db_app1'
def db_for_read(self, model, **hints):
"""
Attempts to read auth and contenttypes models go to self.db_name.
"""
if model._meta.app_label in self.route_app_labels:
return self.db_name
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth and contenttypes models go to self.db_name.
"""
if model._meta.app_label in self.route_app_labels:
return self.db_name
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth or contenttypes apps is
involved.
"""
if (
obj1._meta.app_label in self.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the auth and contenttypes apps only appear in the
self.db_name database.
"""
if app_label in self.route_app_labels:
return db == self.db_name
return None
Update DATABASE_ROUTERS in settings.py
settings.py
DATABASE_ROUTERS = ['app1.dbRouter.App1DBRouter', 'app2.dbRouter.App2DBRouter']

Categories

Resources