Refs #26445 -- Allowed using UserManager.create_user()/create_superuser() in migrations.
Used app config to lookup user model in _create_user(). Thanks Markus Holtermann for the review and initial patch. Thanks Simon Charette for the implementation idea.
This commit is contained in:
parent
d1409f51ff
commit
7af8f41273
|
@ -1,5 +1,7 @@
|
|||
from django.apps import apps
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.mail import send_mail
|
||||
|
@ -134,9 +136,13 @@ class UserManager(BaseUserManager):
|
|||
if not username:
|
||||
raise ValueError('The given username must be set')
|
||||
email = self.normalize_email(email)
|
||||
username = self.model.normalize_username(username)
|
||||
# Lookup the real model class from the global app registry so this
|
||||
# manager method can be used in migrations. This is fine because
|
||||
# managers are by definition working on the real model.
|
||||
GlobalUserModel = apps.get_model(self.model._meta.app_label, self.model._meta.object_name)
|
||||
username = GlobalUserModel.normalize_username(username)
|
||||
user = self.model(username=username, email=email, **extra_fields)
|
||||
user.set_password(password)
|
||||
user.password = make_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
|
|
|
@ -10,8 +10,12 @@ from django.contrib.auth.models import (
|
|||
)
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core import mail
|
||||
from django.db import connection, migrations
|
||||
from django.db.migrations.state import ModelState, ProjectState
|
||||
from django.db.models.signals import post_save
|
||||
from django.test import SimpleTestCase, TestCase, override_settings
|
||||
from django.test import (
|
||||
SimpleTestCase, TestCase, TransactionTestCase, override_settings,
|
||||
)
|
||||
|
||||
from .models import IntegerUsernameUser
|
||||
from .models.with_custom_email_field import CustomEmailField
|
||||
|
@ -101,7 +105,12 @@ class LoadDataWithNaturalKeysAndMultipleDatabasesTestCase(TestCase):
|
|||
self.assertEqual(perm_other.content_type_id, other_objects[0].id)
|
||||
|
||||
|
||||
class UserManagerTestCase(TestCase):
|
||||
class UserManagerTestCase(TransactionTestCase):
|
||||
available_apps = [
|
||||
'auth_tests',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
]
|
||||
|
||||
def test_create_user(self):
|
||||
email_lowercase = 'normal@normal.com'
|
||||
|
@ -156,6 +165,30 @@ class UserManagerTestCase(TestCase):
|
|||
for char in password:
|
||||
self.assertIn(char, allowed_chars)
|
||||
|
||||
def test_runpython_manager_methods(self):
|
||||
def forwards(apps, schema_editor):
|
||||
UserModel = apps.get_model('auth', 'User')
|
||||
user = UserModel.objects.create_user('user1', password='secure')
|
||||
self.assertIsInstance(user, UserModel)
|
||||
|
||||
operation = migrations.RunPython(forwards, migrations.RunPython.noop)
|
||||
project_state = ProjectState()
|
||||
project_state.add_model(ModelState.from_model(User))
|
||||
project_state.add_model(ModelState.from_model(Group))
|
||||
project_state.add_model(ModelState.from_model(Permission))
|
||||
project_state.add_model(ModelState.from_model(ContentType))
|
||||
new_state = project_state.clone()
|
||||
with connection.schema_editor() as editor:
|
||||
operation.state_forwards('test_manager_methods', new_state)
|
||||
operation.database_forwards(
|
||||
'test_manager_methods',
|
||||
editor,
|
||||
project_state,
|
||||
new_state,
|
||||
)
|
||||
user = User.objects.get(username='user1')
|
||||
self.assertTrue(user.check_password('secure'))
|
||||
|
||||
|
||||
class AbstractBaseUserTests(SimpleTestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue