Fixed #29616 -- Fixed createsuperuser for user models that don't have a password field.
This commit is contained in:
parent
89d4d41240
commit
8b43e9b1af
|
@ -17,6 +17,9 @@ class NotRunningInTTYException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
PASSWORD_FIELD = 'password'
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Used to create a superuser.'
|
help = 'Used to create a superuser.'
|
||||||
requires_migrations_checks = True
|
requires_migrations_checks = True
|
||||||
|
@ -60,11 +63,15 @@ class Command(BaseCommand):
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
username = options[self.UserModel.USERNAME_FIELD]
|
username = options[self.UserModel.USERNAME_FIELD]
|
||||||
database = options['database']
|
database = options['database']
|
||||||
|
|
||||||
# If not provided, create the user with an unusable password
|
|
||||||
password = None
|
|
||||||
user_data = {}
|
user_data = {}
|
||||||
verbose_field_name = self.username_field.verbose_name
|
verbose_field_name = self.username_field.verbose_name
|
||||||
|
try:
|
||||||
|
self.UserModel._meta.get_field(PASSWORD_FIELD)
|
||||||
|
except exceptions.FieldDoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# If not provided, create the user with an unusable password.
|
||||||
|
user_data[PASSWORD_FIELD] = None
|
||||||
try:
|
try:
|
||||||
if options['interactive']:
|
if options['interactive']:
|
||||||
# Same as user_data but with foreign keys as fake model
|
# Same as user_data but with foreign keys as fake model
|
||||||
|
@ -109,18 +116,16 @@ class Command(BaseCommand):
|
||||||
if field.remote_field:
|
if field.remote_field:
|
||||||
fake_user_data[field_name] = field.remote_field.model(input_value)
|
fake_user_data[field_name] = field.remote_field.model(input_value)
|
||||||
|
|
||||||
# Prompt for a password.
|
# Prompt for a password if the model has one.
|
||||||
while password is None:
|
while PASSWORD_FIELD in user_data and user_data[PASSWORD_FIELD] is None:
|
||||||
password = getpass.getpass()
|
password = getpass.getpass()
|
||||||
password2 = getpass.getpass('Password (again): ')
|
password2 = getpass.getpass('Password (again): ')
|
||||||
if password != password2:
|
if password != password2:
|
||||||
self.stderr.write("Error: Your passwords didn't match.")
|
self.stderr.write("Error: Your passwords didn't match.")
|
||||||
password = None
|
|
||||||
# Don't validate passwords that don't match.
|
# Don't validate passwords that don't match.
|
||||||
continue
|
continue
|
||||||
if password.strip() == '':
|
if password.strip() == '':
|
||||||
self.stderr.write("Error: Blank passwords aren't allowed.")
|
self.stderr.write("Error: Blank passwords aren't allowed.")
|
||||||
password = None
|
|
||||||
# Don't validate blank passwords.
|
# Don't validate blank passwords.
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
@ -129,7 +134,8 @@ class Command(BaseCommand):
|
||||||
self.stderr.write('\n'.join(err.messages))
|
self.stderr.write('\n'.join(err.messages))
|
||||||
response = input('Bypass password validation and create user anyway? [y/N]: ')
|
response = input('Bypass password validation and create user anyway? [y/N]: ')
|
||||||
if response.lower() != 'y':
|
if response.lower() != 'y':
|
||||||
password = None
|
continue
|
||||||
|
user_data[PASSWORD_FIELD] = password
|
||||||
else:
|
else:
|
||||||
# Non-interactive mode.
|
# Non-interactive mode.
|
||||||
if username is None:
|
if username is None:
|
||||||
|
@ -147,7 +153,6 @@ class Command(BaseCommand):
|
||||||
else:
|
else:
|
||||||
raise CommandError('You must use --%s with --noinput.' % field_name)
|
raise CommandError('You must use --%s with --noinput.' % field_name)
|
||||||
|
|
||||||
user_data['password'] = password
|
|
||||||
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
|
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
|
||||||
if options['verbosity'] >= 1:
|
if options['verbosity'] >= 1:
|
||||||
self.stdout.write("Superuser created successfully.")
|
self.stdout.write("Superuser created successfully.")
|
||||||
|
|
|
@ -5,6 +5,7 @@ from .custom_user import (
|
||||||
from .invalid_models import CustomUserNonUniqueUsername
|
from .invalid_models import CustomUserNonUniqueUsername
|
||||||
from .is_active import IsActiveTestUser1
|
from .is_active import IsActiveTestUser1
|
||||||
from .minimal import MinimalUser
|
from .minimal import MinimalUser
|
||||||
|
from .no_password import NoPasswordUser
|
||||||
from .uuid_pk import UUIDUser
|
from .uuid_pk import UUIDUser
|
||||||
from .with_foreign_key import CustomUserWithFK, Email
|
from .with_foreign_key import CustomUserWithFK, Email
|
||||||
from .with_integer_username import IntegerUsernameUser
|
from .with_integer_username import IntegerUsernameUser
|
||||||
|
@ -13,6 +14,6 @@ from .with_last_login_attr import UserWithDisabledLastLoginField
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'CustomUser', 'CustomUserWithoutIsActiveField', 'CustomPermissionsUser',
|
'CustomUser', 'CustomUserWithoutIsActiveField', 'CustomPermissionsUser',
|
||||||
'CustomUserWithFK', 'Email', 'ExtensionUser', 'IsActiveTestUser1',
|
'CustomUserWithFK', 'Email', 'ExtensionUser', 'IsActiveTestUser1',
|
||||||
'MinimalUser', 'UUIDUser', 'CustomUserNonUniqueUsername',
|
'MinimalUser', 'NoPasswordUser', 'UUIDUser', 'CustomUserNonUniqueUsername',
|
||||||
'IntegerUsernameUser', 'UserWithDisabledLastLoginField',
|
'IntegerUsernameUser', 'UserWithDisabledLastLoginField',
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class UserManager(BaseUserManager):
|
||||||
|
def _create_user(self, username, **extra_fields):
|
||||||
|
user = self.model(username=username, **extra_fields)
|
||||||
|
user.save(using=self._db)
|
||||||
|
return user
|
||||||
|
|
||||||
|
def create_superuser(self, username=None, **extra_fields):
|
||||||
|
return self._create_user(username, **extra_fields)
|
||||||
|
|
||||||
|
|
||||||
|
class NoPasswordUser(AbstractBaseUser):
|
||||||
|
password = None
|
||||||
|
last_login = None
|
||||||
|
username = models.CharField(max_length=50, unique=True)
|
||||||
|
|
||||||
|
USERNAME_FIELD = 'username'
|
||||||
|
objects = UserManager()
|
|
@ -879,6 +879,40 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
||||||
|
|
||||||
test(self)
|
test(self)
|
||||||
|
|
||||||
|
@override_settings(AUTH_USER_MODEL='auth_tests.NoPasswordUser')
|
||||||
|
def test_usermodel_without_password(self):
|
||||||
|
new_io = StringIO()
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
call_command(
|
||||||
|
'createsuperuser',
|
||||||
|
interactive=False,
|
||||||
|
stdin=MockTTY(),
|
||||||
|
stdout=new_io,
|
||||||
|
stderr=new_io,
|
||||||
|
username='username',
|
||||||
|
)
|
||||||
|
self.assertEqual(new_io.getvalue().strip(), 'Superuser created successfully.')
|
||||||
|
|
||||||
|
test(self)
|
||||||
|
|
||||||
|
@override_settings(AUTH_USER_MODEL='auth_tests.NoPasswordUser')
|
||||||
|
def test_usermodel_without_password_interactive(self):
|
||||||
|
new_io = StringIO()
|
||||||
|
|
||||||
|
@mock_inputs({'username': 'username'})
|
||||||
|
def test(self):
|
||||||
|
call_command(
|
||||||
|
'createsuperuser',
|
||||||
|
interactive=True,
|
||||||
|
stdin=MockTTY(),
|
||||||
|
stdout=new_io,
|
||||||
|
stderr=new_io,
|
||||||
|
)
|
||||||
|
self.assertEqual(new_io.getvalue().strip(), 'Superuser created successfully.')
|
||||||
|
|
||||||
|
test(self)
|
||||||
|
|
||||||
|
|
||||||
class MultiDBCreatesuperuserTestCase(TestCase):
|
class MultiDBCreatesuperuserTestCase(TestCase):
|
||||||
multi_db = True
|
multi_db = True
|
||||||
|
|
Loading…
Reference in New Issue