Reputation: 1
I have one database with multitples schemas, and I try to use routers to manage record informations. (https://www.amvtek.com/blog/posts/2014/Jun/13/accessing-multiple-postgres-schemas-from-django/)
In my django settings:
# myproject/myproject/settings.py
...
DATABASE_ROUTERS = [
'routers.sharingRouter.SharingRouter',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'options': '-c search_path=django'
},
'NAME': 'myproject',
'USER': 'user1',
'PASSWORD': 'pwd',
'HOST': '127.0.0.1',
'PORT': '5433',
'CHARSET': 'UTF8',
},
'sharing_writers': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'options': '-c search_path=sharing'
},
'NAME': 'myproject',
'USER': 'user2',
'PASSWORD': 'pwd',
'HOST': '127.0.0.1',
'PORT': '5433',
'CHARSET': 'UTF8',
},
'sharing_readers': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'options': '-c search_path=sharing'
},
'NAME': 'myproject',
'USER': 'user3',
'PASSWORD': 'pwd',
'HOST': '127.0.0.1',
'PORT': '5433',
'CHARSET': 'UTF8',
},
}
...
In my router: (like in official documentation: https://docs.djangoproject.com/en/3.1/topics/db/multi-db/)
# myproject/routers/sharingRouter.py
class SharingRouter(object):
""".
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {
'sharing',
}
def db_for_read(self, model, **hints):
""".
Attempts to read sharing models go to sharing_readers.
"""
if model._meta.app_label in self.route_app_labels:
return 'sharing_readers'
return None
def db_for_write(self, model, **hints):
""".
Attempts to write sharing model go to sharing_writers.
"""
if model._meta.app_label in self.route_app_labels:
return 'sharing_writers'
return None
def allow_relation(self, obj1, obj2, **hints):
""".
Allow relations if a model in the sharing app 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 sharing app only appear in the
'sharing_writers' database.
"""
if app_label in self.route_app_labels:
return db == 'sharing_writers'
return None
In my app model:
# myproject/sharing/models.py
from django.db import models
class Gender(models.Model):
"""TODO."""
name = models.CharField(
max_length=50,
unique=True,
null=False,
blank=False
)
class Meta():
"""TODO."""
app_label = 'sharing'
I have more models, but it's just for example. You can see, app_label is defined.
When use migration command to record django data in first
./manage.py migrate
result is correct:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
Use default database, fine.
And in second time, I use makemigration and migrate for sharing app:
./manage.py makemigrations --name sharing sharing
Migrations for 'sharing':
sharing/migrations/0001_sharing.py
- Create model Gender
./manage.py migrate sharing
Operations to perform:
Apply all migrations: sharing
Running migrations:
Applying sharing.0001_sharing... OK
Is ok to, but not because sharing information use default database and not sharing_writers as if sharingRouter.py, and allow_migrate function, is not use. It's ok now, thanks @IainShelvington
I try to force it to add a defaultRouter, but not change. I try this too: Django multiple databases error with routes
===Editing===
I add a default router:
class DefaultRouter(object):
""".
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {
'sharing',
}
def db_for_read(self, model, **hints):
""".
Attempts to read default django go to default.
"""
if model._meta.app_label not in self.route_app_labels:
return 'default'
return None
def db_for_write(self, model, **hints):
""".
Attempts to write default django go to default.
"""
if model._meta.app_label not in self.route_app_labels:
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
""".
Allow relations if a model in the default app is
involved.
"""
if (
obj1._meta.app_label not in self.route_app_labels or
obj2._meta.app_label not in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
""".
Make sure the sharing app only appear in the
'default' database.
"""
if app_label not in self.route_app_labels:
print(f"default router - : {db} {app_label} {model_name} {hints} ")
return db == 'default'
return None
And I add a print on SharingRouter.allow_migrate:
if app_label in self.route_app_labels:
print(f"sharing router - : {db} {app_label} {model_name} {hints} ")
return db == 'sharing_writers'
return None
I add new DefautRouter on settings, like this:
DATABASE_ROUTERS = [
'routers.sharingRouter.SharingRouter',
'routers.defaultRouter.DefaultRouter',
]
DefaultRouter in last.
I lauch migrate command without 'sharing' app in INSTALLED_APPS
./manage.py migrate
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth group {}
default router - : default auth group {}
default router - : default auth group {}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default sessions session {}
default router - : default sessions session {}
default router - : default sessions session {}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial...default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
OK
Applying auth.0001_initial...default router - : default auth permission {'model': <class '__fake__.Permission'>}
default router - : default auth group {'model': <class '__fake__.Group'>}
default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying admin.0001_initial...default router - : default admin logentry {'model': <class '__fake__.LogEntry'>}
OK
Applying admin.0002_logentry_remove_auto_add...default router - : default admin logentry {'model': <class '__fake__.LogEntry'>}
OK
Applying admin.0003_logentry_add_action_flag_choices...default router - : default admin logentry {'model': <class '__fake__.LogEntry'>}
OK
Applying contenttypes.0002_remove_content_type_name...default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
OK
Applying auth.0002_alter_permission_name_max_length...default router - : default auth permission {'model': <class '__fake__.Permission'>}
OK
Applying auth.0003_alter_user_email_max_length...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0004_alter_user_username_opts...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0005_alter_user_last_login_null...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0008_alter_user_username_max_length...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0009_alter_user_last_name_max_length...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying auth.0010_alter_group_name_max_length...default router - : default auth group {'model': <class '__fake__.Group'>}
OK
Applying auth.0011_update_proxy_permissions...default router - : default auth None {}
OK
Applying auth.0012_alter_user_first_name_max_length...default router - : default auth user {'model': <class '__fake__.User'>}
OK
Applying sessions.0001_initial...default router - : default sessions session {'model': <class '__fake__.Session'>}
OK
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default auth permission {'model': <class '__fake__.Permission'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default auth permission {'model': <class '__fake__.Permission'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default auth permission {'model': <class '__fake__.Permission'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
default router - : default auth permission {'model': <class '__fake__.Permission'>}
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
Use a good router, DefaultRouter.
I launch makemigrations with sharing in INSTALLED_APPS
./manage.py makemigrations --name sharing sharing
sharing router - : default sharing Gender {}
default router - : default admin LogEntry {}
sharing router - : musics_readers sharing Gender {}
default router - : musics_readers admin LogEntry {}
default router - : musics_readers sessions Session {}
default router - : musics_readers auth Permission {}
default router - : musics_readers auth Group {}
default router - : musics_readers auth User {}
default router - : musics_readers contenttypes ContentType {}
sharing router - : musics_writers sharing Gender {}
default router - : musics_writers admin LogEntry {}
default router - : musics_writers sessions Session {}
default router - : musics_writers auth Permission {}
default router - : musics_writers auth Group {}
default router - : musics_writers auth User {}
default router - : musics_writers contenttypes ContentType {}
sharing router - : sharing_readers sharing Gender {}
default router - : sharing_readers admin LogEntry {}
default router - : sharing_readers sessions Session {}
default router - : sharing_readers auth Permission {}
default router - : sharing_readers auth Group {}
default router - : sharing_readers auth User {}
default router - : sharing_readers contenttypes ContentType {}
sharing router - : sharing_writers sharing Gender {}
Migrations for 'sharing':
sharing/migrations/0001_sharing.py
- Create model Gender
I see when it's Gender model, use sharing router.
When I use migrate --plan, confirm it:
./manage.py migrate sharing --plan
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default admin logentry {'model': <class 'django.contrib.admin.models.LogEntry'>}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth permission {'model': <class 'django.contrib.auth.models.Permission'>}
default router - : default auth group {}
default router - : default auth group {}
default router - : default auth group {}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth group {'model': <class 'django.contrib.auth.models.Group'>}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default auth user {'model': <class 'django.contrib.auth.models.User'>}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default contenttypes contenttype {'model': <class 'django.contrib.contenttypes.models.ContentType'>}
default router - : default sessions session {}
default router - : default sessions session {}
default router - : default sessions session {}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
default router - : default sessions session {'model': <class 'django.contrib.sessions.models.Session'>}
sharing router - : default sharing gender {}
sharing router - : default sharing gender {}
sharing router - : default sharing gender {'model': <class 'sharing.models.Gender'>}
sharing router - : default sharing gender {'model': <class 'sharing.models.Gender'>}
sharing router - : default sharing gender {'model': <class 'sharing.models.Gender'>}
Planned operations:
sharing.0001_sharing
Create model Gender
But when I lauch migrate command, sharing models tables not record.
...
Operations to perform:
Apply all migrations: sharing
default router - : default contenttypes contenttype {'model': <class '__fake__.ContentType'>}
Running migrations:
Applying sharing.0001_sharing...sharing router - : default sharing gender {'model': <class '__fake__.Gender'>}
OK
I see the db is not good,
# print(f"sharing router - : {db} {app_label} {model_name} {hints} ")
sharing router - : default sharing gender {'model': <class '__fake__.Gender'>}
But I return the good database 'sharing_writers' on SharingRouter.allow_migrate
Why not use the good database ?
I think I forgot something but I don't no what. I hope my explication is clear. Sorry for my english writing.
Thanks for your help.
Upvotes: 0
Views: 817
Reputation: 1
I found the solution. In fact you need to use database parameter, like this:
./manage.py migrate sharing --database='sharing_writers'
I don't quite understand why I need to define it if I use routers. Why it is ont automatic ? And I find that the documentation it's not clear about this.
Well, I closed it.
Thanks
Upvotes: 0