Django TestCase not using transactions on secondary database
Asked Answered
P

2

8

I am using Django 1.3.1. I have two databases, some of my models live in one database, some in the other. Both databases are contrib.gis.db.backends.postgis databases.

To my surprise, Django's TestCase isn't rolling back changes I made in the secondary database between tests.

In the following code, myproject.models.WellOwner is a very simple model that basically only has a field "name". The router says that it should be in the secondary database. The assertion in the first test succeeds, the second test fails:

from django.test import TestCase
from myproject.models import WellOwner

class SimpleTest(TestCase):
    def test1(self):
        WellOwner.objects.create(name="Remco")
        self.assertEquals(1, WellOwner.objects.count())  # Succeeds

class SimpleTest2(TestCase):
    def test2(self):
        # I would expect to have an empty database at this point
        self.assertEquals(0, WellOwner.objects.count())  # Fails!

I assume that Django wraps this in a transaction on the default database, but not on the secondary database. Is this a known problem? Is there a fix? In 1.4 perhaps? My Google-fu is failing.

(if I change DATABASE_ROUTERS to [] in settings so that everything goes into the same database, the problem disappears)

I'll add the whole code of the router, in case it helps:

SECONDARY_MODELS = ('WellOwner', ...)

import logging
logger = logging.getLogger(__name__)


class GmdbRouter(object):
    """Keep some models in a secondary database."""

    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'gmdb':
            if model._meta.object_name in SECONDARY_MODELS:
                return 'secondary'

        return None

    def db_for_write(self, model, **hints):
        # Same criteria as for reading
        return self.db_for_read(model, **hints)

    def allow_syncdb(self, db, model):
        if db == 'secondary':
            if model._meta.app_label in ('sites', 'south'):
                # Hack for bug https://code.djangoproject.com/ticket/16353
                # When testing, create django_site and south in both databases
                return True

            return self.db_for_read(model) == 'secondary'
        else:
            # Some other db
            if model._meta.app_label == 'gmdb':
                # Our models go in the other db if they don't go into secondary
                return self.db_for_read(model) != 'secondary'

            # Some other model in some other db, no opinion
            return None
Pitchy answered 12/4, 2012 at 10:7 Comment(3)
you should include your routers in the question. That is where the problem could be.Heptameter
I have a similar case where the connection._rollback() fix for integrityerror does not work anymore as soon as I move the model to a seperate database. Also postgis models, so maybe there is something wrong in django.contrib.gis.db.modelsFikes
hey RemcoGerlich, did you ever find a resolution? I'm struggling with the same issue #12206355Conker
C
6

Try this:

class MyTestCase(TestCase):
    multi_db = True

https://docs.djangoproject.com/en/1.2/topics/testing/#django.test.TestCase.multi_db

Conker answered 5/9, 2012 at 21:25 Comment(0)
L
1

Note that multi_db is deprecated since Django 2.2.
The new option to use is databases.

Lukash answered 23/10, 2020 at 19:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.