How to automate creating a Django super user

Setting up a Django super user may be a requirement in your test setup code. The commands used to create users are interactive by default and unfortunately do not allow you to pass in the user’s password as an argument or a flag on the command line. This is a security measure, but it isn’t great for test code. In this post, I will show you two ways of getting around this limitation through the use of environment variables and using a custom management command.

Using environment variables

One way to automate creating a super user is to run the createsuperuser command in a non interactive way. To do this, run it with the --no-input flag. This forces it to look for user credentials in the environment variables. To set the user credentials as environment variables in Linux, use the export command. Once the username and password variables have been set, run the createsuperuser command with the --no-input flag like this:

✗ export DJANGO_SUPERUSER_EMAIL=test@test.com
✗ export DJANGO_SUPERUSER_PASSWORD=testpass1234
✗ python manage.py createsuperuser --no-input
Superuser created successfully.

The steps for setting environment variables will depend on your operating system and tool you’re using. The above is very useful when running tests in Linux docker containers.

Creating a custom management command

An alternative approach to the above is to create your own version of createsuperuser command that takes a password flag. I found a Stackoverflow answer that addresses this very situation. To make your own management command, create a folder in your Django app and call it management. In management folder add a __init__.py file to turn the folder into into a package. Create a subfolder called commands in the management directory. Add an __init__.py file in the commands folder as well and create a python file that’ll contain the code for your custom createsuperuser action. You can name it createsuperuser2.

At this point, your directory structure should look something like this:

management
├── __init__.py
└── commands
    ├── __init__.py
    └── createsuperuser2.py

1 directory, 3 files

Add the following to the createsuperuser2.py file:

from django.contrib.auth.management.commands import createsuperuser
from django.core.management import CommandError


class Command(createsuperuser.Command):
    help = "Create a superuser, and allow password to be provided"

    def add_arguments(self, parser):
        super(Command, self).add_arguments(parser)
        parser.add_argument(
            "--password",
            dest="password",
            default=None,
            help="Specifies the password for the superuser.",
        )
        parser.add_argument(
            "--preserve",
            dest="preserve",
            default=False,
            action="store_true",
            help="Exit normally if the user already exists.",
        )

    def handle(self, *args, **options):
        password = options.get("password")
        username = options.get("username")
        database = options.get("database")

        if password and not username:
            raise CommandError("--username is required if specifying --password")

        if username and options.get("preserve"):
            exists = (
                self.UserModel._default_manager.db_manager(database)
                .filter(username=username)
                .exists()
            )
            if exists:
                self.stdout.write("User exists, exiting normally due to --preserve")
                return

        super(Command, self).handle(*args, **options)

        if password:
            user = self.UserModel._default_manager.db_manager(database).get(
                username=username
            )
            user.set_password(password)
            user.save()

The code above subclasses the createsuperuser command and allows you to set and update the password using a commandline flag. Note however that this code will only work for standard User models. If your code uses a custom user model with a username field that is different from the traditional username, you will need to modify the script above to use the correct username field you’re using in your project. Save the file. To run it, do the following:

python manage.py createsuperuser2 --username admin2 --password mysecretadminpassword

If everything went well, a new user will be created.

Conclusion

The methods shown above are great for automating creating a super user in a non interactive way. It is important to note that passing a password as a part of the command is not safe as it will be visible in the process list. This means that the examples shown above should only be used in test systems for dummy users that won’t have access to real or sensitive information. Thanks for reading.

 

Vuyisile