sql >> Database >  >> RDS >> PostgreSQL

Django-eenheidstest mislukt voor meerdere Postgres-schema's

Schema's worden niet in veel andere DB-engines gebruikt. Door een schema in uw modellen op te geven, heeft u een afhankelijkheid in uw code voor postgres geïntroduceerd.

Er zijn twee routes die u kunt nemen om uw probleem op te lossen;

Ten eerste kunt u een standaardzoekpad toevoegen aan uw postgres-gebruiker. Het nadeel van deze aanpak is dat schema's niet meer kunnen worden gebruikt voor namespaces, maar het voordeel is dat als je database ooit naar een andere engine verandert, je code prima zal functioneren. U kunt uw tabellen een naam geven door een standaardmanier te kiezen om uw tabellen een naam te geven, vergelijkbaar met de manier waarop Django dit standaard doet (bijv. appName_className)

Er zijn twee manieren om dit te bereiken. Het postgres-commando om het op deze manier te doen is:

ALTER USER (your user) SET search_path = "$user",(schema1),(schema2),(schema3),(...)

De enige manier om dit te doen voor django zou zijn:

# Warning! This is untested, I just glanced at the docs and it looks right.
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        # some configuration here
        'OPTIONS': {
            'options': '-c search_path=schema1,schema2,schema3'
        }
    }
}

U wilt ook het volgende wijzigen:

db_table = 'cedirData\".\"persons'

naar:

db_table = 'persons'

Als bonus kun je nu het volgende gebruiken:

manage.py inspectdb > models.py

wat een leuke functie is, op die manier hoef je je bestaande database niet met de hand te kopiëren.

Deze oplossing zal u echter niet helpen, als schemanaamruimten zwaar werden gebruikt in uw database en andere toepassingen ervan afhankelijk zijn. Een andere benadering zou zijn om een ​​aangepaste testrunner te schrijven om die schema's in uw testdatabase te maken. Dit is iets ingewikkelder dan de bovenstaande benadering en kan nogal rommelig zijn. Ik raad het niet echt aan om dit te doen, maar als je geïnteresseerd bent, kan ik proberen te helpen.

Een minder rommelige, maar meer 'hacky' manier zou zijn om meta simpelweg te negeren wanneer tests worden uitgevoerd. Dit zou ook een testrunner zijn.

from django.test.simple import DjangoTestSuiteRunner
from django.db.models.loading import get_models

class SchemaModelTestRunner(DjangoTestSuiteRunner):
    """Docstring"""
    def setup_test_environment(self, *args, **kwargs):
        self.original_db_tables = {}
        self.schema_models = [m for m in get_models()
                                 if '"."' in m._meta.db_table]
        for m in self.schema_models:
            schema, table = m._meta.db_table.split('"."')
            self.original_db_tables[m] = m._meta.db_table
            m._meta.db_table = 'schema_'+schema+'_table_'+table

        super(SchemaModelTestRunner, self).setup_test_environment(*args,
                                                                   **kwargs)
    def teardown_test_environment(self, *args, **kwargs):
        super(SchemaModelTestRunner, self).teardown_test_environment(*args,
                                                                      **kwargs)
        # reset models
        for m in self.schema_models:
            m._meta.db_table = self.original_db_tables[m]

U wilt dit ook als testrunner definiëren in uw settings.py-bestand.




  1. Hoe voer je SQL uit vanuit een bash-script?

  2. Maak een externe sleutel met jpa

  3. Een aangepaste SQL Server Docker-afbeelding maken bovenop de officiële afbeelding

  4. Is er een manier om OracleCommand.BindByName te dwingen standaard waar te zijn voor ODP.NET?