Preston
Preston

Reputation: 8187

django migrations test: 'Manager' object has no attribute error

I'm testing a django migration inspired by this article. This method/ the MigrationTestCase works fine outside the user model, but seems to fall down when trying to access my custom user model.

Here is the test method:

from kapsule.tests.test_migrations import MigrationTestCase

from django.db import connection
from django.db.migrations.executor import MigrationExecutor
from django.test.testcases import TransactionTestCase


class MigrationTestCase(TransactionTestCase):
    """
    A Test case for testing migrations
    """

    # These must be defined by subclasses.
    migrate_from = None
    migrate_to = None

    def setUp(self):
        super(MigrationTestCase, self).setUp()

        self.executor = MigrationExecutor(connection)
        self.executor.migrate(self.migrate_from)

    def migrate_to_dest(self):
        self.executor.loader.build_graph()  # reload.
        self.executor.migrate(self.migrate_to)

    @property
    def old_apps(self):
        return self.executor.loader.project_state(self.migrate_from).apps

    @property
    def new_apps(self):
        return self.executor.loader.project_state(self.migrate_to).apps


class SummaryTestCase(MigrationTestCase):
    """
    Test db migration
    """

    migrate_from = [('accounts', '0003_subscription')]
    migrate_to = [('accounts', '0004_create_tokens')]

    def setup_before_migration(self):
        User = self.old_apps.get_model('accounts', 'CustomUser')

        demo_user = User.objects.create_user(email='[email protected]',  # nosec
                                             password='ni likey no lightey',
                                             first_name='Contact',
                                             last_name='Me',
                                             company='Group',
                                             country='FR',
                                             )
    def test_token_populated(self):
        # runs setup
        self.setup_before_migration()

Here is (a truncated version of) my user model (including my custom user manager):

class CustomUserManager(BaseUserManager):

    def _create_user(self, email, password, **extra_fields):
        ...
        return user

    def create_user(self, email, password, **extra_fields):
        ...
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        ...
        return self._create_user(email, password, **extra_fields)

class CustomUser(AbstractUser):
    """
    Replace username by email as required and unique.
    """
    # Hide username
    username = None

    # Overidde other fields
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(_('first name'))
    ...

    # Override the UserManager with our custom one (for objects creation)
    objects = CustomUserManager()

I see the error:

AttributeError: 'Manager' object has no attribute 'create_user'

but i don't understand why, as this is clearly defined on the model, and works correctly outside of the test case.

Any help that you can give is greatly appreciated.

EDIT:

Traceback:

======================================================================
ERROR: test_token_populated (accounts.tests.test_migrations.SummaryTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/code/accounts/tests/test_migrations.py", line 59, in test_token_populated
    self.setup_before_migration()
  File "/code/accounts/tests/test_migrations.py", line 43, in setup_before_migration
    demo_user = User.objects.create_user(email='[email protected]',  # nosec
AttributeError: 'Manager' object has no attribute 'create_user'

Upvotes: 1

Views: 1387

Answers (1)

Nafees Anwar
Nafees Anwar

Reputation: 6598

You are using historical model to create user in your test case (setup_before_migration method). Custom managers are not serialized by default to be used with historical models. Please set use_in_migrations = True in custom user manager, delete your migrations and make them again. like this

class CustomUserManager(BaseUserManager):
    use_in_migrations = True

    ...

You can read more about it here (historical models) and here (use_in_migrations)

Upvotes: 4

Related Questions