django 迁移测试:'Manager' object has no attribute 错误

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

我正在测试受 this article 启发的 django 迁移。此方法/ MigrationTestCase 在用户模型之外工作正常,但在尝试访问我的自定义用户模型时似乎失败了。

测试方法如下:

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='contact@me.fr',  # 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()

这是我的用户模型(包括我的自定义用户管理器)的(截断版本):

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()

我看到错误:

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

但我不明白为什么,因为这在模型上有明确定义,并且在测试用例之外也能正常工作。

非常感谢您提供的任何帮助。

编辑:

回溯:

======================================================================
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='contact@me.fr',  # nosec
AttributeError: 'Manager' object has no attribute 'create_user'

您正在使用历史模型在测试用例中创建用户(setup_before_migration 方法)。默认情况下,自定义管理器不会序列化以与历史模型一起使用。请在自定义用户管理器中设置 use_in_migrations = True,删除您的迁移并重新进行。像这样

class CustomUserManager(BaseUserManager):
    use_in_migrations = True

    ...

您可以阅读更多相关信息here (historical models) and here (use_in_migrations)