问题
I've created a django project and then two apps, app1 and app2. I want that both apps share a mysql database('nameofDB' to mysql, 'mydb' to django). I added the database to DATABASES in settings.py and for each app I created a dbrouter file, and added each router to DATABASE_ROUTERS. Also in settings.py added each app to INSTALLED_APPS.
My problem is when I try to make
python manage.py syncdb --database=mydb
Because it doesn't sync both apps(only app1). It says:
Creating tables ...
Creating table app1_model1
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
Here my settings.py:
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'),
},
'mydb':{
'ENGINE': 'django.db.backends.mysql',
'NAME': 'nameofDB',
'USER':'username',
'PASSWORD':'password',
}
}
DATABASE_ROUTERS = ['app1.dbRouter.App1DBRouter', 'app2.dbRouter.App2DBRouter']
Here my models:
app1/models.py:
class Model1(models.Model):
name = models.CharField(max_length=100)
app2/models.py:
class Model2(models.Model):
name = models.CharField(max_length=100)
Here are my dbrouters
app1/dbRouter.py
class App1DBRouter(object):
def db_for_read(self,model, **hints):
if model._meta.app_label == 'app1':
return 'mydb'
return None
def db_for_write(self,model, **hints):
if model._meta.app_label == 'app1':
return 'mydb'
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 == 'mydb':
return model._meta.app_label == 'app1'
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 'mydb'
return None
def db_for_write(self,model, **hints):
if model._meta.app_label == 'app2':
return 'mydb'
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 == 'mydb':
return model._meta.app_label == 'app2'
elif model._meta.app_label == 'app2':
return False
return None
What's wrong with it? What should I do? Thanks in advance! :)
回答1:
I agree with Daniel Roseman. When you have two or more apps using the same db than you migth be fine with one router. In general perhaps one router per each non default database?
But if you really need two routers here is a solution.
The Django root db router tries all routers from DATABASE_ROUTERS as long as allow_syncdb returns None. Thus App1DBRouter.allow_syncdb needs to return None (instead of False) for model._meta.app_label == 'app2' and db == 'mydb'. This way App2DBRouter.allow_syncdb will have a chance to be called.
I got your syncdb working with following changes
class App1DBRouter(object):
...
def allow_syncdb(self,db, model):
if db == 'mydb':
if model._meta.app_label == 'app1':
return True
elif model._meta.app_label == 'app1':
return False
return None
class App2DBRouter(object):
...
def allow_syncdb(self,db, model):
if db == 'mydb':
if model._meta.app_label == 'app2':
return True
else:
return False
elif model._meta.app_label == 'app2':
return False
return None
回答2:
Maybe app2_model2 was created before, check that!
You could do it like this:
settings.py
DATABASE_APPS_MAPPING = {'app1': 'mydb', 'app2': 'mydb'}
DATABASE_ROUTERS = ['path.router.DatabaseAppsRouter']
router.py
from django.conf import settings
class DatabaseAppsRouter(object):
"""
A router to control all database operations on models for different
databases.
In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database.
Settings example:
DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
"""
def db_for_read(self, model, **hints):
"""Point all read operations to the specific database."""
if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
return None
def db_for_write(self, model, **hints):
"""Point all write operations to the specific database."""
if settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
return None
def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation between apps that use the same database."""
db_obj1 = settings.DATABASE_APPS_MAPPING.get(obj1._meta.app_label)
db_obj2 = settings.DATABASE_APPS_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
return None
def allow_syncdb(self, db, model):
"""Make sure that apps only appear in the related database."""
if db in settings.DATABASE_APPS_MAPPING.values():
return settings.DATABASE_APPS_MAPPING.get(model._meta.app_label) == db
elif settings.DATABASE_APPS_MAPPING.has_key(model._meta.app_label):
return False
return None
来源:https://stackoverflow.com/questions/22031369/sharing-mysql-database-between-apps-django-with-database-routers