diff options
author | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-05-31 10:47:28 +0100 |
---|---|---|
committer | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-05-31 10:47:28 +0100 |
commit | 0b5270eab393fad20faa7a6a9720af18c97b1773 (patch) | |
tree | de32d3300256be1bfc8626361970efa32b133ce5 | |
parent | e9851a7d51afffea2a5679934ad6284c0835cfa2 (diff) | |
download | factory-boy-0b5270eab393fad20faa7a6a9720af18c97b1773.tar factory-boy-0b5270eab393fad20faa7a6a9720af18c97b1773.tar.gz |
Properly handle custom Django managers (Closes #201).
The actual behavior of Django with custom managers and inherited
abstract models is rather complex, so this had to be adapted to the
actual Django source code.
-rw-r--r-- | docs/changelog.rst | 4 | ||||
-rw-r--r-- | factory/django.py | 9 | ||||
-rw-r--r-- | tests/djapp/models.py | 11 | ||||
-rw-r--r-- | tests/test_django.py | 13 |
4 files changed, 35 insertions, 2 deletions
diff --git a/docs/changelog.rst b/docs/changelog.rst index 0cbd4af..c871ce8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,10 @@ ChangeLog thus allowing to pass in a lazy iterator such as a Django queryset (i.e ``factory.Iterator(models.MyThingy.objects.all())``). +*Bugfix:* + + - :issue:`201`: Properly handle custom Django managers when dealing with abstract Django models. + .. _v2.5.2: 2.5.2 (2015-04-21) diff --git a/factory/django.py b/factory/django.py index 74e4fdb..e4a3ea7 100644 --- a/factory/django.py +++ b/factory/django.py @@ -115,7 +115,14 @@ class DjangoModelFactory(base.Factory): if model_class is None: raise base.AssociatedClassError("No model set on %s.%s.Meta" % (cls.__module__, cls.__name__)) - manager = model_class.objects + + try: + manager = model_class.objects + except AttributeError: + # When inheriting from an abstract model with a custom + # manager, the class has no 'objects' field. + manager = model_class._default_manager + if cls._meta.database != DEFAULT_DB_ALIAS: manager = manager.using(cls._meta.database) return manager diff --git a/tests/djapp/models.py b/tests/djapp/models.py index 68b9709..cadefbc 100644 --- a/tests/djapp/models.py +++ b/tests/djapp/models.py @@ -110,3 +110,14 @@ class WithCustomManager(models.Model): foo = models.CharField(max_length=20) objects = CustomManager() + + +class AbstractWithCustomManager(models.Model): + custom_objects = CustomManager() + + class Meta: + abstract = True + + +class FromAbstractWithCustomManager(AbstractWithCustomManager): + pass diff --git a/tests/test_django.py b/tests/test_django.py index bde8efe..b8e7ccb 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -755,10 +755,21 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertSignalsReactivated() -class DjangoCustomManagerTestCase(django_test.TestCase): +@unittest.skipIf(django is None, "Django not installed.") +class DjangoCustomManagerTestCase(unittest.TestCase): def test_extra_args(self): + # Our CustomManager will remove the 'arg=' argument. model = WithCustomManagerFactory(arg='foo') + def test_with_manager_on_abstract(self): + class ObjFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.FromAbstractWithCustomManager + + # Our CustomManager will remove the 'arg=' argument, + # invalid for the actual model. + ObjFactory.create(arg='invalid') + if __name__ == '__main__': # pragma: no cover unittest.main() |