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 import auth
|
||||||
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
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.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
|
@ -134,9 +136,13 @@ class UserManager(BaseUserManager):
|
||||||
if not username:
|
if not username:
|
||||||
raise ValueError('The given username must be set')
|
raise ValueError('The given username must be set')
|
||||||
email = self.normalize_email(email)
|
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 = self.model(username=username, email=email, **extra_fields)
|
||||||
user.set_password(password)
|
user.password = make_password(password)
|
||||||
user.save(using=self._db)
|
user.save(using=self._db)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,12 @@ from django.contrib.auth.models import (
|
||||||
)
|
)
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core import mail
|
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.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 import IntegerUsernameUser
|
||||||
from .models.with_custom_email_field import CustomEmailField
|
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)
|
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):
|
def test_create_user(self):
|
||||||
email_lowercase = 'normal@normal.com'
|
email_lowercase = 'normal@normal.com'
|
||||||
|
@ -156,6 +165,30 @@ class UserManagerTestCase(TestCase):
|
||||||
for char in password:
|
for char in password:
|
||||||
self.assertIn(char, allowed_chars)
|
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):
|
class AbstractBaseUserTests(SimpleTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue