Commit 75ff7b8f authored by Anubhav Joshi's avatar Anubhav Joshi Committed by Tim Graham
Browse files

Fixed #21832 -- Updated prompt, tests, and docs to show that USERNAME_FIELD...

Fixed #21832 -- Updated prompt, tests, and docs to show that USERNAME_FIELD supports FK after 9bc2d766.

Also added get_input_data() hook in createsuperuser.

Thanks Chris Jerdonek and Tim Graham for review.
parent 136a3ffe
Loading
Loading
Loading
Loading
+26 −19
Original line number Diff line number Diff line
@@ -87,20 +87,14 @@ class Command(BaseCommand):
                # Get a username
                verbose_field_name = self.username_field.verbose_name
                while username is None:
                    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
                        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:
                        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
+3 −3
Original line number Diff line number Diff line
@@ -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()
+13 −8
Original line number Diff line number Diff line
@@ -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)
+10 −0
Original line number Diff line number Diff line
@@ -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``
----------------------

+2 −1
Original line number Diff line number Diff line
@@ -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`
Loading