Fixed #21832 -- Updated prompt, tests, and docs to show that USERNAME_FIELD supports FK after 9bc2d76
.
Also added get_input_data() hook in createsuperuser. Thanks Chris Jerdonek and Tim Graham for review.
This commit is contained in:
parent
136a3ffe21
commit
75ff7b8fb8
|
@ -87,20 +87,14 @@ class Command(BaseCommand):
|
|||
# Get a username
|
||||
verbose_field_name = self.username_field.verbose_name
|
||||
while username is None:
|
||||
input_msg = capfirst(verbose_field_name)
|
||||
if default_username:
|
||||
input_msg += " (leave blank to use '%s')" % default_username
|
||||
username_rel = self.username_field.rel
|
||||
input_msg = force_str('%s%s: ' % (input_msg,
|
||||
' (%s.%s)' % (username_rel.to._meta.object_name, username_rel.field_name) if username_rel else ''))
|
||||
username = self.get_input_data(self.username_field, input_msg, default_username)
|
||||
if not username:
|
||||
input_msg = capfirst(verbose_field_name)
|
||||
if default_username:
|
||||
input_msg = "%s (leave blank to use '%s')" % (
|
||||
input_msg, default_username)
|
||||
raw_value = input(force_str('%s: ' % input_msg))
|
||||
|
||||
if default_username and raw_value == '':
|
||||
raw_value = default_username
|
||||
try:
|
||||
username = self.username_field.clean(raw_value, None)
|
||||
except exceptions.ValidationError as e:
|
||||
self.stderr.write("Error: %s" % '; '.join(e.messages))
|
||||
username = None
|
||||
continue
|
||||
try:
|
||||
self.UserModel._default_manager.db_manager(database).get_by_natural_key(username)
|
||||
|
@ -115,12 +109,9 @@ class Command(BaseCommand):
|
|||
field = self.UserModel._meta.get_field(field_name)
|
||||
user_data[field_name] = options.get(field_name)
|
||||
while user_data[field_name] is None:
|
||||
raw_value = input(force_str('%s%s: ' % (capfirst(field.verbose_name), ' (%s.%s)' % (field.rel.to._meta.object_name, field.rel.field_name) if field.rel else '')))
|
||||
try:
|
||||
user_data[field_name] = field.clean(raw_value, None)
|
||||
except exceptions.ValidationError as e:
|
||||
self.stderr.write("Error: %s" % '; '.join(e.messages))
|
||||
user_data[field_name] = None
|
||||
message = force_str('%s%s: ' % (capfirst(field.verbose_name),
|
||||
' (%s.%s)' % (field.rel.to._meta.object_name, field.rel.field_name) if field.rel else ''))
|
||||
user_data[field_name] = self.get_input_data(field, message)
|
||||
|
||||
# Get a password
|
||||
while password is None:
|
||||
|
@ -153,3 +144,19 @@ class Command(BaseCommand):
|
|||
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
|
||||
if options['verbosity'] >= 1:
|
||||
self.stdout.write("Superuser created successfully.")
|
||||
|
||||
def get_input_data(self, field, message, default=None):
|
||||
"""
|
||||
Override this method if you want to customize data inputs or
|
||||
validation exceptions.
|
||||
"""
|
||||
raw_value = input(message)
|
||||
if default and raw_value == '':
|
||||
raw_value = default
|
||||
try:
|
||||
val = field.clean(raw_value, None)
|
||||
except exceptions.ValidationError as e:
|
||||
self.stderr.write("Error: %s" % '; '.join(e.messages))
|
||||
val = None
|
||||
|
||||
return val
|
||||
|
|
|
@ -40,7 +40,7 @@ class CustomUserManager(BaseUserManager):
|
|||
|
||||
class CustomUserWithFKManager(BaseUserManager):
|
||||
def create_superuser(self, username, email, group, password):
|
||||
user = self.model(username=username, email_id=email, group_id=group)
|
||||
user = self.model(username_id=username, email_id=email, group_id=group)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
@ -96,8 +96,8 @@ class CustomUser(AbstractBaseUser):
|
|||
|
||||
|
||||
class CustomUserWithFK(AbstractBaseUser):
|
||||
username = models.CharField(max_length=30, unique=True)
|
||||
email = models.ForeignKey(Email, to_field='email')
|
||||
username = models.ForeignKey(Email, related_name='primary')
|
||||
email = models.ForeignKey(Email, to_field='email', related_name='secondary')
|
||||
group = models.ForeignKey(Group)
|
||||
|
||||
custom_objects = CustomUserWithFKManager()
|
||||
|
|
|
@ -350,15 +350,15 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
|||
self.assertIs(command.stdin, sys.stdin)
|
||||
|
||||
@override_settings(AUTH_USER_MODEL='auth.CustomUserWithFK')
|
||||
def test_required_field_with_fk(self):
|
||||
def test_fields_with_fk(self):
|
||||
new_io = six.StringIO()
|
||||
group = Group.objects.create(name='mygroup')
|
||||
email = Email.objects.create(email='mymail@gmail.com')
|
||||
call_command(
|
||||
'createsuperuser',
|
||||
interactive=False,
|
||||
username='user',
|
||||
email='mymail@gmail.com',
|
||||
username=email.pk,
|
||||
email=email.email,
|
||||
group=group.pk,
|
||||
stdout=new_io,
|
||||
skip_checks=True,
|
||||
|
@ -366,7 +366,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
|||
command_output = new_io.getvalue().strip()
|
||||
self.assertEqual(command_output, 'Superuser created successfully.')
|
||||
u = CustomUserWithFK._default_manager.get(email=email)
|
||||
self.assertEqual(u.username, "user")
|
||||
self.assertEqual(u.username, email)
|
||||
self.assertEqual(u.group, group)
|
||||
|
||||
non_existent_email = 'mymail2@gmail.com'
|
||||
|
@ -375,19 +375,24 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
|||
call_command(
|
||||
'createsuperuser',
|
||||
interactive=False,
|
||||
username='user',
|
||||
username=email.pk,
|
||||
email=non_existent_email,
|
||||
stdout=new_io,
|
||||
skip_checks=True,
|
||||
)
|
||||
|
||||
@override_settings(AUTH_USER_MODEL='auth.CustomUserWithFK')
|
||||
def test_required_fields_with_fk_interactive(self):
|
||||
def test_fields_with_fk_interactive(self):
|
||||
new_io = six.StringIO()
|
||||
group = Group.objects.create(name='mygroup')
|
||||
email = Email.objects.create(email='mymail@gmail.com')
|
||||
|
||||
@mock_inputs({'password': "nopasswd", 'username': "user", 'email': "mymail@gmail.com", 'group': group.pk})
|
||||
@mock_inputs({
|
||||
'password': 'nopasswd',
|
||||
'username (email.id)': email.pk,
|
||||
'email (email.email)': email.email,
|
||||
'group (group.id)': group.pk,
|
||||
})
|
||||
def test(self):
|
||||
call_command(
|
||||
'createsuperuser',
|
||||
|
@ -400,7 +405,7 @@ class CreatesuperuserManagementCommandTestCase(TestCase):
|
|||
command_output = new_io.getvalue().strip()
|
||||
self.assertEqual(command_output, 'Superuser created successfully.')
|
||||
u = CustomUserWithFK._default_manager.get(email=email)
|
||||
self.assertEqual(u.username, 'user')
|
||||
self.assertEqual(u.username, email)
|
||||
self.assertEqual(u.group, group)
|
||||
|
||||
test(self)
|
||||
|
|
|
@ -1478,6 +1478,16 @@ it when running interactively.
|
|||
Use the ``--database`` option to specify the database into which the superuser
|
||||
object will be saved.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
You can subclass the management command and override ``get_input_data()`` if you
|
||||
want to customize data input and validation. Consult the source code for
|
||||
details on the existing implementation and the method's parameters. For example,
|
||||
it could be useful if you have a ``ForeignKey`` in
|
||||
:attr:`~django.contrib.auth.models.CustomUser.REQUIRED_FIELDS` and want to
|
||||
allow creating an instance instead of entering the primary key of an existing
|
||||
instance.
|
||||
|
||||
``django.contrib.gis``
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ Minor features
|
|||
* The ``max_length`` of :attr:`Permission.name
|
||||
<django.contrib.auth.models.Permission.name>` has been increased from 50 to
|
||||
255 characters. Please run the database migration.
|
||||
* :attr:`~django.contrib.auth.models.CustomUser.REQUIRED_FIELDS` now supports
|
||||
* :attr:`~django.contrib.auth.models.CustomUser.USERNAME_FIELD` and
|
||||
:attr:`~django.contrib.auth.models.CustomUser.REQUIRED_FIELDS` now supports
|
||||
:class:`~django.db.models.ForeignKey`\s.
|
||||
|
||||
:mod:`django.contrib.formtools`
|
||||
|
|
|
@ -508,6 +508,15 @@ password resets. You must then provide some key implementation details:
|
|||
...
|
||||
USERNAME_FIELD = 'identifier'
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
:attr:`USERNAME_FIELD` now supports
|
||||
:class:`~django.db.models.ForeignKey`\s. Since there is no way to pass
|
||||
model instances during the :djadmin:`createsuperuser` prompt, expect the
|
||||
user to enter the value of :attr:`~django.db.models.ForeignKey.to_field`
|
||||
value (the :attr:`~django.db.models.Field.primary_key` by default) of an
|
||||
existing instance.
|
||||
|
||||
.. attribute:: REQUIRED_FIELDS
|
||||
|
||||
A list of the field names that will be prompted for when creating a
|
||||
|
|
Loading…
Reference in New Issue