【问题标题】:Is using multiple databases and South together possible?是否可以同时使用多个数据库和 South?
【发布时间】:2011-10-25 03:31:11
【问题描述】:

我目前的项目正在扩展地理内容,所以我正在尝试集成 GeoDjango 并为初学者导入一些 shapefile。我的设置包括以下内容:

  1. MySQL 5.0 作为“默认”数据库,以前是唯一的数据库。
  2. Spatialite 作为“gis”数据库,只能用于从 shapefile 导入区域
  3. 整个项目都在使用South

现在我已经在一个新应用中为我的区域创建了一个 GeoDjango 模型。像往常一样,我已经完成了./manage.py schemamigration --initial,当我尝试执行./manage.py migrate $my_new_app --database="gis" 时,它以django.db.utils.DatabaseError: no such table: south_migrationhistory 失败,我猜这是正确的,因为south_migrationhistory 在我的主数据库中。

是否有人对此类设置有任何经验并可以帮助我?

编辑:我更改了标题,因为我意识到这个问题实际上并不是 GeoDjango 特有的。

【问题讨论】:

    标签: django django-south django-orm


    【解决方案1】:

    我改进的灵魂:

    在另一个数据库中创建表south_migrationhistory

    ./manage.py syncdb --database="my_db_name_for_apps"
    

    您现在可以使用标准:

    ./manage.py migrate my_app
    

    这是我的实际db_router.py

    # -*- coding: UTF-8 -*-
    apps =['app1', 'app2' ]    
    db_name = 'my_db_name_for_apps'
    
    class sh_router(object):
        """A router to control all database operations on models from applications in apps"""
    
        def db_for_read(self, model, **hints):
            """Point all operations on apps models to db_name"""
            if model._meta.app_label in apps :
                return db_name
            return None
    
        def db_for_write(self, model, **hints):
            """Point all operations on apps models to db_name"""
            if model._meta.app_label in apps:
                return db_name
            return None
    
        def allow_relation(self, obj1, obj2, **hints):
            """Allow any relation if a model in apps is involved"""
            if obj1._meta.app_label in apps or obj2._meta.app_label in apps:
                return True
            return None
    
        def allow_syncdb(self, db, model):
            """Make sure the apps only appears on the db_name db"""
            if model._meta.app_label in ['south']:
                return True
            if db == db_name:
                return model._meta.app_label in apps
            elif model._meta.app_label in apps:
                return False
            return None
    

    【讨论】:

    • 您可能不想在“allow_relation”方法中允许跨数据库关系。你可能想要if obj1._state.db == obj2._state.db 而不是if obj1._meta.app_label...
    • 第一个 syncdb 命令将在目标数据库中创建所有应用程序的表,以及 django auth 表——而不仅仅是您需要的 south_migrationhistory 表。
    • allow_migrate 允许确定哪些模型应该进入给定的数据库。
    【解决方案2】:

    我发现所有答案都有些不准确,因此,这里是一个摘要。

    首先,大家当然应该阅读the South documentation中关于多个数据库的那几行:)

    执行此操作的方法是手动编辑迁移文件以指向正确的数据库。最简单的方法是将其添加到所有文件的顶部:

    from south.db import dbs
    db = dbs['name_of_you_nondefault_db']
    

    基本原因是 South 没有从您的数据库路由器中获取数据库名称。这个特性根本没有实现,可能永远不会随着 Django 1.7 的到来而实现。

    但要开始,请运行:

    python manage.py syncdb
    

    现在,您有了 south_migrationhistory 表。然后要迁移您的特殊数据库,请执行以下操作:

    python manage.py migrate
    

    不会在每个数据库中创建 south_migrationhistory,只会在默认数据库中创建。因此迁移历史可以集中保存。

    具有同一应用程序的不同副本的多个数据库

    如果您需要在多个数据库中迁移同一个应用程序,则不应使用单一的迁移历史记录。

    相反,像这样创建 south_migrationhistory:

    python manage.py sql south | PGOPTIONS="-c search_path=NAME_OF_YOUR_SCHEMA_TO_CREATE_IN" python manage.py dbshell --database=name_of_you_nondefault_db
    

    现在,您应该运行迁移,指定 BOTH app_label 和要从中获取 south_migrationhistory 的数据库。

    python manage.py migrate name_of_app --database=name_of_you_nondefault_db
    

    【讨论】:

    • 我试过你的覆盖数据库的例子,但它似乎仍然没有应用我的迁移。初始迁移有效,但后续迁移无效。
    【解决方案3】:

    在我的db_router.py 文件中,我只是在我的应用列表中取消注释'south' 应用。 我启动syncdb 以在otherdb 数据库中创建表south_migrationhistory

    ./manage.py syncdb --database="otherdb"
    

    然后在我的应用列表中再次评论'south' 应用。

    您现在可以使用标准

    ./manage.py migrate my_app --database="otherdb"
    

    这是我的db_router.py

    #-*- coding: UTF-8 -*-
    
    apps =['app1',
         'app2',
         'south', # <<<---------------- Comment / Uncomment here
       ]
    
    db_name = 'otherdb'
    
    class sh_router(object):
    """A router to control all database operations on models from applications in apps"""
    
      def db_for_read(self, model, **hints):
        """Point all operations on apps models to db_name"""
        if model._meta.app_label in apps :
            return db_name
        return None
    
      def db_for_write(self, model, **hints):
        """Point all operations on apps models to db_name"""
        if model._meta.app_label in apps:
            return db_name
        return None
    
      def allow_relation(self, obj1, obj2, **hints):
        """Allow any relation if a model in apps is involved"""
        if obj1._meta.app_label in apps or obj2._meta.app_label in apps:
            return True
        return None
    
      def allow_syncdb(self, db, model):
        """Make sure the apps only appears on the db_name db"""
        if db == db_name:
            return model._meta.app_label in apps
        elif model._meta.app_label in apps:
            return False
        return None
    

    【讨论】:

    • 这与我想出的解决方案几乎相同。我唯一缺少的是评论/取消评论南方。谢谢。
    • 请注意,这仍然是一个不完整的解决方案,因为您无法运行 ./manage.py migrate 来迁移两个数据库。迁移另一个数据库时,South 将获取一个数据库的迁移。
    【解决方案4】:

    正如 Tomasz 所说,您也必须同步您的“gis”数据库才能创建所有必需的表,包括 south_migrationhistory。

    ./manage.py syncdb --database=gis
    

    【讨论】:

    • 您需要指定一个路由器,否则您会将所有应用程序添加到另一个数据库中,这可能不是您想要的。
    【解决方案5】:

    似乎 Django 1.7 在其数据库路由器类中有 allow_migrate() 来解决这个问题。

    对于早期的 Django:

    • 您需要将 south_migrationhistory 放在要迁移的任何数据库中
    • 做一个常规的syncdb 将所有常规的auth_* 等表放在default db 中
    • 这会将 south_migrationhistory 放入 default
    • 不要做syncdb --database=other,这会复制所有的auth_*等。 other 中的表格
    • 改为将south_migrationhistory 表从default 复制到other,例如

      sqlite3 main.sqlite ".sc south_migrationhistory" | sqlite3 other.sqlite

      或等效的 pg_dump 命令或其他任何东西

    • 然后使用migrate --database=other

    至少在您迁移到 1.7 之前,这一切都在正确的位置:-)

    【讨论】:

      【解决方案6】:

      我知道这个帖子很旧,但我遇到了同样的问题,Google 帮我找到了那个帖子。

      所以首先你需要改变你进行数据迁移的方式:

          def forwards(self, orm):
          "Write your forwards methods here."                               
              obj = orm.Obj()
              obj.name = 'my name'
              obj.save(using=db.db_alias)
      

      变量 db.db_alias 包含要使用的数据库的名称,因此您需要使用“usgin”执行所有操作并使用 db.db_alias 作为数据库名称。

      然后你运行你的迁移 ./mange migrate App --database=DB_NAME

      在架构迁移的情况下,只需像 south 一样直接使用 db.function。

      【讨论】:

        【解决方案7】:

        您可能希望在两个数据库中都有 south_migrationhistory,因此 syncdb 为 south 应用程序的“要点”。那么您的迁移应该会顺利进行。

        【讨论】:

        • 任何想法如何让 South 将其放入两个数据库中?
        猜你喜欢
        • 2012-12-22
        • 1970-01-01
        • 1970-01-01
        • 2019-04-26
        • 1970-01-01
        • 1970-01-01
        • 2013-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多