django-admin.py: Unknown command: ‘createsuperuser’

tl;dr

When you need to create a superuser, the official Django documentation says to run django-admin.py createsuperuser. Instead, run the following:

$ python manage.py createsuperuser

The Details

While putting together a tutorial for Django, I started to explore how a project behaves if I didn’t create a superuser when running syncdb for the first time. My first question was how do you create a superuser after running syncdb.

I found the following documentation to create a superuser:

django-admin.py createuser

django-admin.py createuser

https://docs.djangoproject.com/en/1.5/ref/django-admin/#django-admin-createsuperuser

Following the documentation, I ran django-admin.py createsuperuser and got an “unknown command error.” Here is the full output for this set of steps:

(djangobox)$ python manage.py syncdb
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): no
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
(djangobox)$ django-admin.py createsuperuser
Unknown command: 'createsuperuser'
Type 'django-admin.py help' for usage.
(djangobox)$ 

So I looked in my project’s settings.py to find that django.contrib.auth was indeed installed. So what gives? In my opinion, the official Django documentation is wrong or misleading, depending on which side of the hair you split. Let me explain.

When you create a superuser, you are creating one for a specific project. Therefore django-admin.py needs to know which project is the target. The conventional way to perform commands on existing projects is to use manage.py, which provides the project and settings information for the Django admin tools. To create a superuser for a Django project, run the following:

$ python manage.py createsuperuser

This allows us to create a superuser if we said no when we ran python manage.py syncdb to instantiate the initial project database. We can also add additional superusers if we want.

Back to the error we got when we tried to create a superuser with django-admin:

(djangobox)$ django-admin.py createsuperuser
Unknown command: 'createsuperuser'
Type 'django-admin.py help' for usage.
(djangobox)$ 

The reason this command failed is that the createsuperuser command is from the django.contrib.auth package, which is not loaded when you run django-admin.py with the default installation configuration (at least without specifying a project or database). These tools, django-admin.py and the project specific manage.py are convenience scripts around ManagementUtility in the django.core.management package. This utility system is extensible. When you add a package to the INSTALLED_APPS dictionary in a project’s settings.py file, it will add management commands, if it has any, to manage.py. Run manage.py without parameters, and you will see what commands are available:

Available subcommands:

[auth]
    changepassword
    createsuperuser

[django]
    cleanup
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    runfcgi
    shell
    sql
    sqlall
    sqlclear
    sqlcustom
    sqlflush
    sqlindexes
    sqlinitialdata
    sqlsequencereset
    startapp
    startproject
    syncdb
    test
    testserver
    validate

[sessions]
    clearsessions

[staticfiles]
    collectstatic
    findstatic
    runserver

when you run django-admin.py on its own, it only shows what is under the [django] list of subcommands.

When you read the source code to django-admin.py, you’ll see something like the following:

#!/Users/jbaldwin/code/djangobox/bin/python
from django.core import management

if __name__ == "__main__":
management.execute_from_command_line()

When you read the source code to manage.py, you’ll see something like:

#!/usr/bin/env python
import os
import sys 

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

You see the commonality: both call django.core.management’s method execute_from_command_line.  This function is a wrapper around the ManagementUtility class in the django.core.management package. No project contexts are provided to django-admin.py, but is provided in manage.py. The directory which contains manage.py will have the project directory (in this case “mysite”), which has the project’s settings.py file. manage.py sets an environment variable for the project and the settings file, then calls the convenience function, passing our parameters to it. If you are interested in poking around the Django source, ManagementUtility is in django.core.management.__init__.py.

To continue on with my explanation, lets look to the official Django docs. Read the red underlined text.

django-admin-manage-py

This is not actually the case. manage.py does not wrap around django-admin.py. I’m not clear why this is stated. This is, in implementation, not accurate. They are both thin wrappers around django.core.management. There could be a misunderstanding of the documentation writers that got carried forward and hasn’t been fixed. It could have been how Django operated prior to version 1.0. Or it is a conceptual simplification: The interface behavior of manage.py acts as if it is a thin wrapper around django-admin.py, since it provides the project specific context, while django-admin.py does not. At this time, I don’t know, and this is a minor nit about the generally excellent documentation, which has helped Django gain its popularity. My thanks to the documenters for all their good work.

Hopefully this post has shed light on some of the mechanics of the Django admin scripts. The main takeaway should be that when you read the djangodocs and they use django-admin.py for commands specific to a project and that project is not part of the parameters, then use manage.py instead.

Advertisements
Tagged with: , , , ,
Posted in Computing, Django, Programming, Python, Web Frameworks