python データベース - Djangoはテストを実行する際にルータを無視しますか?





指定 結合 (4)


testコマンドで--settingsフラグを使用します。 path.to.test.pyモジュールでは、 python manage.py test --settings=app.settings.testです。 ルートで悩む必要はありません。いつでもどこでも設定フラグを使ってテストを呼び出すようにしてください。

app.settings.test.pyで、DATABASESデータ構造を再定義します。

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

これにより、テストを実行するときに別のデータベースを使用することができます。 さらに、sqlite3をエンジンとして使用すると、データベースがメモリ上にあるため、テストが非常に高速に実行されます。

テストにsqlite3データベースを使用すると、何百ものテストを数秒で実行できます。 その結果、テストを頻繁に実行することができます。 私は通常、作業を保存し、テストを1つのアクションで実行するためのキーをマップします。

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

それが役に立つと願っています!

私は2つのデータベース接続を使用するdjangoアプリケーションを持っています:

  1. アプリが生成する実際のデータに接続するには
  2. 参照マスタデータシステムに、それは私のコントロールの外に完全に維持されます

私が持っている問題は、私のwebappが2番目のデータベースのデータに絶対に触れることができないということです。 私は2つのサブアプリケーションを使用して、各データベース接続ごとに1つの問題を解決しました。 私はルーターファイルを作成して、マイグレーションを行い、最初のアプリケーションに書き込んでいます

また、2番目のアプリのすべてのモデルを管理していない

model.meta.managed = False

オプション。

確かに、2番目のデータベースに接続しているユーザーは読み取り専用アクセス権を持っています

これは、移行と実行には問題ありません。 ただし、djangoテストケースを使用してテストを実行しようとすると、Djangoは2番目のデータベース接続でtest_データベースを削除して作成しようとします。

Djangoが2番目の接続で更新/削除/挿入/削除/切り捨てをしないことを確認するにはどうすればいいですか?

2番目のデータベースを作成するのではなく、最初のデータベースを作成するテストを実行するにはどうすればよいですか。

ありがとう!

編集:コード

モデル(2番目のアプリの場合、管理しないでください):

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'

...

ルータ:

__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

設定:

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'),
    },
}

1つのテストケース:

from django.test.testcases import TestCase

__author__ = 'CoesseWa'


class ModelTest(TestCase):

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

このテストを実行したときの出力

... 
Destroying old test user...

(この点の前に、djangoは私の最初の接続= OKのテストデータベースを作成します)

Creating test user...

=>次の行は決して起こらないはずです。 私は読み取り専用ユーザーを使用するために失敗します(幸いにも)

Creating test database for alias 'mdm_db'...

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



あなたは、Pythonモックを使用して2番目のデータベースへの接続を模倣しようとする可能性がありますか? https://pypi.python.org/pypi/mock - 今はpython 3のstdlibの一部です。




私はDATABASES.TEST定義を変更することでこれを解決しました。 私は、 TEST['MIRROR'] = 'default'mdm_dbデータベースエントリに追加しました。

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
        }
    },
}

documentationよると、このオプションはデータベース作成をスキップするために悪用される可能性があります:

ただし、レプリカデータベースはテストミラーとして設定されています(MIRRORテスト設定を使用)。これは、テスト中にレプリカをデフォルトのミラーとして処理する必要があることを示します。

テスト環境が設定されると、レプリカのテストバージョンは作成されません。 代わりに、レプリカへの接続はデフォルトでポイントにリダイレクトされます。

テストを実行すると、2番目のデータベースの作成がスキップされるようになりました。

すべての入力をありがとう!




Bah ...コメントするには評判が足りません...しかし、私は、受け入れられた回答で表現された意見が幾分古いことを指摘したいと思います。 最近のディスカッション(djangoバグ#7634#12785 )によると、auto_nowとauto_now_addはどこにも行きません。 元のディスカッションに行っても、カスタムセーブのRY(DRYのような)に対して強い議論がありますメソッド。

より良い解決策が提供されています(カスタムフィールドタイプ)が、それはdjangoにするための十分な勢いを得ていませんでした。 3行で自分で書くことができます(Jacob Kaplan-Mossの提案です)。

class AutoDateTimeField(models.DateTimeField):
    def pre_save(self, model_instance, add):
        return datetime.datetime.now()

#usage
created_at = models.DateField(default=timezone.now)
updated_at = models.AutoDateTimeField(default=timezone.now)




python django database