From 0b5270eab393fad20faa7a6a9720af18c97b1773 Mon Sep 17 00:00:00 2001 From: Raphaƫl Barrois Date: Sun, 31 May 2015 10:47:28 +0100 Subject: 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. --- docs/changelog.rst | 4 ++++ factory/django.py | 9 ++++++++- tests/djapp/models.py | 11 +++++++++++ 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() -- cgit v1.2.3