代码之家  ›  专栏  ›  技术社区  ›  voodoo14

使用数据库路由器在应用程序Django之间共享(mysql)数据库

  •  2
  • voodoo14  · 技术社区  · 10 年前

    我创建了一个django项目,然后创建了两个应用程序app1和app2。我希望这两个应用程序共享一个mysql数据库(mysql的名称DB,django的名称mydb)。我在settings.py中将数据库添加到了DATABASES,并为每个应用程序创建了一个dbrouter文件,并将每个路由器添加到database_ROUTERS。同样在settings.py中,将每个应用程序添加到INSTALLED_APPS。

    我的问题是当我试图

    python manage.py syncdb --database=mydb
    

    因为它不会同步两个应用程序(只有app1)。上面写着:

    Creating tables ...
    Creating table app1_model1
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    

    这里是我的设置.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']
    

    这里是我的模型:

    app1/型号.py:

    class Model1(models.Model):
        name = models.CharField(max_length=100)
    

    app2/型号.py:

    class Model2(models.Model):
        name = models.CharField(max_length=100)
    

    这是我的数据库路由器

    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
    

    它怎么了?我该怎么办?提前感谢!:)

    2 回复  |  直到 10 年前
        1
  •  2
  •   stephenmm    9 年前

    也许app2_model2是之前创建的,请检查一下!

    你可以这样做:

    设置.py

    DATABASE_APPS_MAPPING = {'app1': 'mydb', 'app2': 'mydb'}
    DATABASE_ROUTERS = ['path.router.DatabaseAppsRouter']
    

    路由器.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
    
        2
  •  1
  •   fragles    10 年前

    我同意丹尼尔·罗斯曼的观点。当你有两个或多个应用程序使用同一个数据库时,一个路由器可能会很好。一般来说,每个非默认数据库可能有一个路由器?

    但如果你真的需要两个路由器,这里有一个解决方案。

    只要allow_syncdb返回None,Django根db路由器就会尝试来自DATABASE_routers的所有路由器。因此,App1DBRouter.allow_syncdb需要为模型返回None(而不是False)_meta.app_label==“app2”和db==“mydb”。这样,App2DBRouter.allow_syncdb将有机会被调用。

    我让你的syncdb进行了以下更改

    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