Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 75ff7b8fb8335e181ad05e1d4244b4295cc7a105 1 parent 136a3ff
@coder9042 coder9042 authored timgraham committed
View
45 django/contrib/auth/management/commands/createsuperuser.py
@@ -87,20 +87,14 @@ def handle(self, *args, **options):
# 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 @@ def handle(self, *args, **options):
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 @@ def handle(self, *args, **options):
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
View
6 django/contrib/auth/tests/custom_user.py
@@ -40,7 +40,7 @@ def create_superuser(self, email, password, date_of_birth):
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 @@ def is_staff(self):
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()
View
21 django/contrib/auth/tests/test_management.py
@@ -350,15 +350,15 @@ def test_passing_stdin(self):
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 @@ def test_required_field_with_fk(self):
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 @@ def test_required_field_with_fk(self):
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 @@ def test(self):
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)
View
10 docs/ref/django-admin.txt
@@ -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``
----------------------
View
3  docs/releases/1.8.txt
@@ -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`
View
9 docs/topics/auth/customizing.txt
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.