Goal: automatically creating a superuser
I’m trying to create a default user, specifically a superuser, in an early data migration, so whenever my Django application is run in my Docker container, it already has a superuser with which I can access the admin site.
I had already tried different options for creating said superuser, and although I have some functioning ones (based on the command
parameter of my docker-compose file), I’ve seen when adding initial data to a Django project, the best practice is to do it through a Data Migration.
My custom user
In my Django project I’ve extended the AbstactBaseUser
so I can change the default username field requirement for the email field. My User
is as such:
class UserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): # Implementation... def create_superuser(self, email, password, **extra_fields): # Implementation... class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField( verbose_name="email address", max_length=255, unique=True, ) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) objects = UserManager() USERNAME_FIELD = "email" REQUIRED_FIELDS = [] def __str__(self): return self.email
Failed attempts
By following the Django documentation here I tried making my superuser in a data migration with the following code, located in a file called 0002_data_superuser in the migrations folder of my app:
def generate_superuser(apps, schema_editor): User = apps.get_model("users.User") User.objects.create_superuser( email=settings.DJANGO_SUPERUSER_EMAIL, password=settings.DJANGO_SUPERUSER_PASSWORD, ) print("nInitial superuser createdn") class Migration(migrations.Migration): dependencies = [ ('users', '0001_initial'), ] operations = [ migrations.RunPython(generate_superuser) ]
When running my docker-compose, however, I run into this error:
AttributeError: 'Manager' object has no attribute 'create_superuser'
I’ve tried debugging by printing the Manager and, indeed, it does not have the create_superuser
necessary for this. My next thought was to try to reproduce what create_superuser
does myself, but I find it quite impossible given that a lot of methods for managing passwords, hashing, normalizing emails and stuff are not available to me.
I gather from all of this that the problem is that the Manager, for some reason, is not available during migrations, and I’d like to know if there’s a solution to this.
Advertisement
Answer
Reproducing create_user
functionality manually
Checking out a bit more the source code of Django I found at there is a way to reproduce the functionality from create_superuser
. By importing BaseUserManager
and the classmethod make_password
from django.contrib.auth.hashers
, I came up with this:
from django.contrib.auth.models import BaseUserManager from django.contrib.auth.hashers import make_password def generate_superuser(apps, schema_editor): User = apps.get_model("users.User") email = settings.DJANGO_SUPERUSER_EMAIL password = settings.DJANGO_SUPERUSER_PASSWORD user = User() user.email = BaseUserManager.normalize_email(email) user.password = make_password(password) user.is_staff = True user.is_superuser = True user.save()
which does the trick.
Still, I don’t like it much as a solution given that it requires reeimplementing an already existing Django method that just is not accessible at this point of the program.