From 636ca46951d710a4b9d9fd61ec1da02294806d3d Mon Sep 17 00:00:00 2001 From: Raphaƫl Barrois Date: Thu, 26 Mar 2015 22:53:15 +0100 Subject: Add support for multidb with Django (Closes #171). The ``factory.django.DjangoModelFactory`` now takes an extra option: ``` class MyFactory(factory.django.DjangoModelFactory): class Meta: model = models.MyModel database = 'replica' ``` This will create all instances of ``models.Model`` in the ``'replica'`` database. --- docs/changelog.rst | 1 + docs/orms.rst | 9 ++++++++- factory/django.py | 8 ++++++-- tests/djapp/settings.py | 3 +++ tests/test_django.py | 10 ++++++++++ tests/test_using.py | 6 ++++++ 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0cf8368..c2da698 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,7 @@ ChangeLog - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`). + - Support non-default databases at the factory level (see :issue:`171`) *Bugfix:* diff --git a/docs/orms.rst b/docs/orms.rst index a0afc40..5105e66 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -42,7 +42,14 @@ All factories for a Django :class:`~django.db.models.Model` should use the .. class:: DjangoOptions(factory.base.FactoryOptions) - The ``class Meta`` on a :class:`~DjangoModelFactory` supports an extra parameter: + The ``class Meta`` on a :class:`~DjangoModelFactory` supports extra parameters: + + .. attribute:: database + + .. versionadded:: 2.5.0 + + All queries to the related model will be routed to the given database. + It defaults to ``'default'``. .. attribute:: django_get_or_create diff --git a/factory/django.py b/factory/django.py index e823ee9..ee5749a 100644 --- a/factory/django.py +++ b/factory/django.py @@ -56,6 +56,7 @@ class DjangoOptions(base.FactoryOptions): def _build_default_options(self): return super(DjangoOptions, self)._build_default_options() + [ base.OptionDefault('django_get_or_create', (), inherit=True), + base.OptionDefault('database', 'default', inherit=True), ] def _get_counter_reference(self): @@ -100,9 +101,12 @@ class DjangoModelFactory(base.Factory): raise base.AssociatedClassError("No model set on %s.%s.Meta" % (cls.__module__, cls.__name__)) try: - return model_class._default_manager # pylint: disable=W0212 + manager = model_class._default_manager # pylint: disable=W0212 except AttributeError: - return model_class.objects + manager = model_class.objects + + manager = manager.using(cls._meta.database) + return manager @classmethod def _get_or_create(cls, model_class, *args, **kwargs): diff --git a/tests/djapp/settings.py b/tests/djapp/settings.py index c051faf..18e43dd 100644 --- a/tests/djapp/settings.py +++ b/tests/djapp/settings.py @@ -34,6 +34,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', }, + 'replica': { + 'ENGINE': 'django.db.backends.sqlite3', + }, } diff --git a/tests/test_django.py b/tests/test_django.py index 4653305..a8f1f77 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -165,6 +165,16 @@ class ModelTests(django_test.TestCase): self.assertRaises(factory.FactoryError, UnsetModelFactory.create) + def test_cross_database(self): + class OtherDBFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.StandardModel + database = 'replica' + + obj = OtherDBFactory() + self.assertFalse(models.StandardModel.objects.exists()) + self.assertEqual(obj, models.StandardModel.objects.using('replica').get()) + @unittest.skipIf(django is None, "Django not installed.") class DjangoPkSequenceTestCase(django_test.TestCase): diff --git a/tests/test_using.py b/tests/test_using.py index 7318f2e..1d7977f 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -69,6 +69,9 @@ class FakeModel(object): def order_by(self, *args, **kwargs): return [1] + def using(self, db): + return self + objects = FakeModelManager() def __init__(self, **kwargs): @@ -1490,6 +1493,9 @@ class BetterFakeModelManager(object): instance.id = 2 return instance, True + def using(self, db): + return self + class BetterFakeModel(object): @classmethod -- cgit v1.2.3