Django 'geo_db_type' 多个数据库的 AttributeError

Django 'geo_db_type' AttributeError with Multiple Databases

背景

我将 Django 与多个数据库一起使用:我有一个 Postgres 数据库和一个 mysql 数据库(充满了我正在慢慢转换到 Postgres 的遗留数据)。

我最近引入了 GeoDjango(以 django.contrib.gis 的形式),带有用于存储 lat/lng 信息的 postgis 扩展作为一个点。该应用程序本身似乎 运行 没问题。我可以很好地从 mysql 数据库和 postgres 数据库访问信息。我什至可以利用新的点字段,这意味着(对我来说)'gis' 东西正在工作和配置。

问题

当我尝试 运行 测试时出现问题。我收到以下错误:

AttributeError: 'DatabaseOperations' object has no attribute 'geo_db_type'

我相信这发生在 mysql 数据库上,因为我首先收到提示,指出 test_db postgress 数据库存在并且需要删除并重新创建。我输入 'yes',它完成了它的工作,然后给我关于 test_mysql 数据库的相同提示。当我回答 'yes' 时,出现错误。

我的旧应用程序的模型不使用任何新字段;导入是 django.db。所以我不明白为什么测试认为我需要对 mysql 数据库进行地理空间操作。

我试过的

1) 注释掉 MySQL 数据库

这确实有效;测试 运行 很好。但是,这不是一个好的解决方案,原因很明显...

2) 将 MySQL 的数据库引擎更改为使用 'django.contrib.gis.db.backends.mysql'

执行此操作时出现不同的错误:

django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')

我猜这是由于我的旧模型中某处的复合键所致。这真的不应该成为问题,我不认为,因为我实际上 运行 在后台运行 MariaDB 10.0.31。此外,django.db.backends.mysql 不会抱怨它。所以我想知道 django.contrib.gis.db.backends.mysql 是否有点过时(因为 MySQL 似乎空间支持有限)。

我不明白为什么测试数据库报错,但应用程序似乎正常工作。

提前感谢您提供的任何帮助!我完全被难住了。

支持信息

我的数据库配置如下所示:

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': os.environ.get('PG_DB_NAME'),
        'USER': os.environ.get('PG_DB_USER'),
        'PASSWORD': os.environ.get('PG_DB_PASS'),
        'HOST': os.environ.get('PG_DB_HOST'),
        'PORT': '',
    },
    'legacy': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.environ.get('MY_DB_NAME'),
        'USER': os.environ.get('MY_DB_USER'),
        'PASSWORD': os.environ.get('MY_DB_PASS'),
        'HOST': os.environ.get('MY_DB_HOST'),
        'PORT': '',
    },  
}

我有一个数据库路由器:

class LegacyRouter(object):
    def db_for_read(self, model, **hints):

        if model._meta.app_label == 'legacy':
            return 'legacy'
        return 'default'

编辑:Hacky 解决方法

因此,经过反复试验后,我发现我可以通过使用单个 postgresql 数据库进行测试来解决这个问题。我通过添加第二个设置文件并在测试时引用它来完成此操作。

from .settings import *

DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': os.environ.get('TEST_DB_NAME'),
        'USER': os.environ.get('TEST_DB_USER'),
        'PASSWORD': os.environ.get('TEST_DB_PASS'),
        'HOST': os.environ.get('TEST_DB_HOST'),
    },
}

DATABASE_ROUTERS = []

在测试时会调用它,例如:

python manage.py test --settings=<module>.test-settings

这对我有用,因为我的遗留数据没有特定于数据库的内容,所以我没有理由不能使用 postgres 进行测试。希望这对其他人有帮助。

编辑:修复

问题出在数据库路由器中。除 'legacy' 应用程序之外的所有应用程序都被路由到 'default' 数据库(预期),而所有应用程序加上 'legacy' 应用程序都被路由到 'legacy' 数据库。

要修复,我需要一个 allow_migrate 函数。这是我的制作方法:

def allow_migrate(self, db, app_label, model_name=None, **hints):

    # Legacy app should only be in legacy database
    # Return true if app is legacy and database is legacy

    if app_label == 'legacy':
        return db == 'legacy'

    # Legacy database should only contain legacy app
    # Return true if app is not legacy and database not legacy

    elif app_label != 'legacy':
        return db != 'legacy'

    else:
        return None

回答

问题出在数据库路由器中。除 'legacy' 应用程序之外的所有应用程序都被路由到 'default' 数据库(预期),而所有应用程序加上 'legacy' 应用程序都被路由到 'legacy' 数据库。

为了解决这个问题,我需要一个 allow_migrate 函数来阻止 'legacy' 应用程序以外的所有应用程序迁移到 'legacy' 数据库中。有关详细信息,请参阅我的问题中的编辑。