Django在运行测试时忽略路由器吗?

时间:2022-02-13 15:38:43

I have a django application that uses 2 database connections:

我有一个django应用程序,它使用两个数据库连接:

  1. To connect to the actual data the app is to produce
  2. 要连接到应用要生成的实际数据
  3. To a reference master data system, that is maintained completely outside my control
  4. 对于一个引用主数据系统,它是完全不受我控制的

The issue that I'm having, is that my webapp can absolutely NOT touch the data in the 2nd database. I solved most of the issues by using 2 (sub)apps, one for every database connection. I created a router file that router any migration, and writing to the first app

我的问题是,我的webapp绝对不能接触到第二数据库中的数据。我通过使用2 (sub)应用程序解决了大部分问题,每个数据库连接一个。我创建了一个路由器文件来路由器任何迁移,并写入到第一个应用

I also made all the models in the 2nd app non managed, using the

我也让第二款应用中的所有模型都不受管理,使用

model.meta.managed = False

option.

选择。

To be sure, the user I connect to the 2nd database has read only access

当然,我连接到第二个数据库的用户具有只读访问权限

This works fine for migrations and running. However, when I try to run tests using django testcase, Django tries to delete and create a test_ database on the 2nd database connection.

这对于迁移和运行都很有效。然而,当我尝试使用django testcase运行测试时,django尝试在第二个数据库连接上删除和创建test_数据库。

How can I make sure that Django will NEVER update/delete/insert/drop/truncate over the 2nd connection

如何确保Django不会在第二个连接上更新/删除/插入/删除/删除/删除/截断

How can I run tests, that do not try to create the second database, but do create the first.

我如何运行测试,不尝试创建第二个数据库,而是创建第一个数据库。

Thanks!

谢谢!

edited: code

编辑:代码

model (for the 2nd app, that should not be managed):

模型(对于第二个app,不应该管理):

from django.db import models


class MdmMeta(object):
    db_tablespace = 'MDM_ADM'
    managed = False
    ordering = ['name']


class ActiveManager(models.Manager):
    def get_queryset(self):
        return super(ActiveManager, self).get_queryset().filter(lifecyclestatus='active')


class MdmType(models.Model):
    entity_guid = models.PositiveIntegerField(db_column='ENTITYGUID')
    entity_name = models.CharField(max_length=255, db_column='ENTITYNAME')

    entry_guid = models.PositiveIntegerField(primary_key=True, db_column='ENTRYGUID')

    name = models.CharField(max_length=255, db_column='NAME')
    description = models.CharField(max_length=512, db_column='DESCRIPTION')

    lifecyclestatus = models.CharField(max_length=255, db_column='LIFECYCLESTATUS')

    # active_manager = ActiveManager()

    def save(self, *args, **kwargs):
        raise Exception('Do not save MDM models!')

    def delete(self, *args, **kwargs):
        raise Exception('Do not delete MDM models!')

    def __str__(self):
        return self.name

    class Meta(MdmMeta):
        abstract = True


# Create your models here.
class MdmSpecies(MdmType):
    class Meta(MdmMeta):
        db_table = 'MDM_SPECIES'
        verbose_name = 'Species'
        verbose_name_plural = 'Species'


class MdmVariety(MdmType):
    class Meta(MdmMeta):
        db_table = 'MDM_VARIETY'
        verbose_name = 'Variety'
        verbose_name_plural = 'Varieties'

...

router:

路由器:

__author__ = 'CoesseWa'

class MdmRouter(object):

    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'mdm':
            # return 'default'
            return 'mdm_db'   # trying to use one database connection
        return 'default'

    def db_for_write(self, model, **hints):
        return 'default'

    def allow_relation(self, obj1, obj2, **hints):
        return None

    def allow_migrate(self, db, model):
        if model._meta.app_label == 'mdm':
            return False

settings:

设置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=1521)))(CONNECT_DATA=(SID=%s)))'
                % (get_env_variable('LIMS_MIGRATION_HOST'), get_env_variable('LIMS_MIGRATION_SID')),
        'USER': 'LIMS_MIGRATION',
        'PASSWORD': get_env_variable('LIMS_MIGRATION_PASSWORD'),
    },
    'mdm_db': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=GB3P)(PORT=1521)))'
                '(CONNECT_DATA=(SID=GB3P)))',
        'USER': 'MDM',
        'PASSWORD': get_env_variable('MDM_DB_PASSWORD'),
    },
}

one testcase:

一个测试用例:

from django.test.testcases import TestCase

__author__ = 'CoesseWa'


class ModelTest(TestCase):

    def test_getting_guid_for_mdm_field(self):
        self.assertIsNotNone(1)

output from when running this tests:

运行测试时的输出:

... 
Destroying old test user...

(before this point, django creates the test database for my first connection = OK)

(在此之前,django为我的第一个连接创建测试数据库= OK)

Creating test user...

=> This next lines should never happen. Fails because I use a read only user (luckily)

=>下一行永远不会发生。失败,因为我使用的是只读用户(幸运的是)

Creating test database for alias 'mdm_db'...

Failed (ORA-01031: insufficient privileges 
Got an error creating the test database: ORA-01031: insufficient privileges

3 个解决方案

#1


10  

I solved this by changing the DATABASES.TEST definition. I added the TEST['MIRROR'] = 'default' to the mdm_db database entry.

我通过改变数据库来解决这个问题。测试的定义。我向mdm_db数据库条目添加了TEST['MIRROR'] = 'default'。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=1521)))(CONNECT_DATA=(SID=%s)))'
                % (get_env_variable('LIMS_MIGRATION_HOST'), get_env_variable('LIMS_MIGRATION_SID')),
        'USER': 'LIMS_MIGRATION',
        'PASSWORD': get_env_variable('LIMS_MIGRATION_PASSWORD'),
    },
    'mdm_db': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=GB3P)(PORT=1521)))'
                '(CONNECT_DATA=(SID=GB3P)))',
        'USER': 'MDM',
        'PASSWORD': get_env_variable('MDM_DB_PASSWORD'),
        'TEST': {
            'MIRROR': 'default',  # Added this setting
        }
    },
}

According to the documentation this option can be abused to skip database creation:

根据文档,这个选项可以被滥用来跳过数据库创建:

However, the replica database has been configured as a test mirror (using the MIRROR test setting), indicating that under testing, replica should be treated as a mirror of default.

但是,副本数据库已经被配置为一个测试镜像(使用镜像测试设置),这表明在测试中,副本应该被视为默认镜像。

When the test environment is configured, a test version of replica will not be created. Instead the connection to replica will be redirected to point at default.

在配置测试环境时,不会创建副本的测试版本。相反,复制的连接将被重定向到默认的点。

Running my tests now skips creation of the second database.

运行我的测试现在跳过了第二个数据库的创建。

Thanks for all the input!!

感谢所有的输入!!

#2


2  

Use the --settings flag with the test command. In the path.to.test.py module, a la python manage.py test --settings=app.settings.test. There is no need to muck around with routes, just make sure that you invoke the tests with the settings flag whenever and where ever you call it.

使用test命令的-settings标志。path.to.test。py模块,一个la python管理。py——设置= app.settings.test测试。没有必要在路由上乱涂乱画,只要确保无论何时何地调用都使用设置标志调用测试即可。

In app.settings.test.py, redefine your DATABASES datastructure:

在app.settings.test。py,重新定义您的数据库数据结构:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
    },
    'mdm_db': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
    },
}

This allows you to use a separate database when running tests. Additionally, if you use sqlite3 as your engine, you'll find that tests run very fast as the database is in memory.

这允许您在运行测试时使用单独的数据库。此外,如果您使用sqlite3作为引擎,您将发现测试运行速度非常快,因为数据库在内存中。

Using sqlite3 databases for testing means that even hundreds of tests can be run within seconds. As a result, you can run your tests very frequently. I typically map a key to save my work and run my tests with one action:

使用sqlite3数据库进行测试意味着即使是数百个测试也可以在数秒内运行。因此,您可以非常频繁地运行您的测试。我通常会映射一个键来保存我的工作,然后用一个动作运行我的测试:

map ,t :up\|!python manage.py test --settings=app.settings.test

Hope that is is helpful!

希望这对你有帮助!

#3


0  

You could try to mock out the connection to the second database using python mocks?https://pypi.python.org/pypi/mock -- now part of the stdlib in python 3.

您可以尝试使用python mock模拟到第二个数据库的连接?https://pypi.python.org/pypi/mock——现在是python 3中的stdlib的一部分。

#1


10  

I solved this by changing the DATABASES.TEST definition. I added the TEST['MIRROR'] = 'default' to the mdm_db database entry.

我通过改变数据库来解决这个问题。测试的定义。我向mdm_db数据库条目添加了TEST['MIRROR'] = 'default'。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=1521)))(CONNECT_DATA=(SID=%s)))'
                % (get_env_variable('LIMS_MIGRATION_HOST'), get_env_variable('LIMS_MIGRATION_SID')),
        'USER': 'LIMS_MIGRATION',
        'PASSWORD': get_env_variable('LIMS_MIGRATION_PASSWORD'),
    },
    'mdm_db': {
        'ENGINE': 'django.db.backends.oracle',
        'NAME': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=GB3P)(PORT=1521)))'
                '(CONNECT_DATA=(SID=GB3P)))',
        'USER': 'MDM',
        'PASSWORD': get_env_variable('MDM_DB_PASSWORD'),
        'TEST': {
            'MIRROR': 'default',  # Added this setting
        }
    },
}

According to the documentation this option can be abused to skip database creation:

根据文档,这个选项可以被滥用来跳过数据库创建:

However, the replica database has been configured as a test mirror (using the MIRROR test setting), indicating that under testing, replica should be treated as a mirror of default.

但是,副本数据库已经被配置为一个测试镜像(使用镜像测试设置),这表明在测试中,副本应该被视为默认镜像。

When the test environment is configured, a test version of replica will not be created. Instead the connection to replica will be redirected to point at default.

在配置测试环境时,不会创建副本的测试版本。相反,复制的连接将被重定向到默认的点。

Running my tests now skips creation of the second database.

运行我的测试现在跳过了第二个数据库的创建。

Thanks for all the input!!

感谢所有的输入!!

#2


2  

Use the --settings flag with the test command. In the path.to.test.py module, a la python manage.py test --settings=app.settings.test. There is no need to muck around with routes, just make sure that you invoke the tests with the settings flag whenever and where ever you call it.

使用test命令的-settings标志。path.to.test。py模块,一个la python管理。py——设置= app.settings.test测试。没有必要在路由上乱涂乱画,只要确保无论何时何地调用都使用设置标志调用测试即可。

In app.settings.test.py, redefine your DATABASES datastructure:

在app.settings.test。py,重新定义您的数据库数据结构:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
    },
    'mdm_db': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
    },
}

This allows you to use a separate database when running tests. Additionally, if you use sqlite3 as your engine, you'll find that tests run very fast as the database is in memory.

这允许您在运行测试时使用单独的数据库。此外,如果您使用sqlite3作为引擎,您将发现测试运行速度非常快,因为数据库在内存中。

Using sqlite3 databases for testing means that even hundreds of tests can be run within seconds. As a result, you can run your tests very frequently. I typically map a key to save my work and run my tests with one action:

使用sqlite3数据库进行测试意味着即使是数百个测试也可以在数秒内运行。因此,您可以非常频繁地运行您的测试。我通常会映射一个键来保存我的工作,然后用一个动作运行我的测试:

map ,t :up\|!python manage.py test --settings=app.settings.test

Hope that is is helpful!

希望这对你有帮助!

#3


0  

You could try to mock out the connection to the second database using python mocks?https://pypi.python.org/pypi/mock -- now part of the stdlib in python 3.

您可以尝试使用python mock模拟到第二个数据库的连接?https://pypi.python.org/pypi/mock——现在是python 3中的stdlib的一部分。