5

I have been stuck to a bottleneck which I have tried to resolve using official docs and other answers here in stackoverflow but still not able to create django superuser programatically in the beanstalk environment.

Current state - a. Application is getting deployed smoothly and I am able to access database from my UI application. basically the entry is getting made in some other table that i have in application.

How I have tried to create superuser -

a. By passing container commands -

Option 1-

container_commands:
  01_migrate:
    command: "django-admin.py migrate"
    leader_only: true
  02_collectstatic:
    command: "django-admin.py collectstatic --noinput"

commands:
  super_user:
    command: "source /opt/python/run/venv/bin/activate && python <appname>/createuser.py"
    leader_only: true

  option_settings:
  "aws:elasticbeanstalk:application:environment":
    DJANGO_SETTINGS_MODULE: "<Appname>.settings"
    PYTHONPATH: "/opt/python/current/app:$PYTHONPATH"

In the logs - I didn't see it trying to run the custom command.

Option 2 -

container_commands:
  01_migrate:
    command: "django-admin.py migrate"
    leader_only: true
  02_collectstatic:
    command: "django-admin.py collectstatic --noinput"
  03_createsuperuser:
    command: "source /opt/python/run/venv/bin/activate && django-admin.py createsuperuser"

  option_settings:
  "aws:elasticbeanstalk:application:environment":
    DJANGO_SETTINGS_MODULE: "<appname>.settings"
    PYTHONPATH: "/opt/python/current/app:$PYTHONPATH"

For this, I created a createsuperuser.py file under /management/commands/ following the structure of init.py in both folders and one createsuperuser.py under commands -

from django.core.management.base import BaseCommand
from django.contrib.auth.models import User


class Command(BaseCommand):

   def handle(self, *args, **options):
      if not User.objects.filter(username="admin").exists():
          User.objects.create_superuser("admin", "admin@gmail.com", "admin")

On this, I got a following message from logs -

Superuser creation skipped due to not running in a TTY. You can run `manage.py createsuperuser` in your project to create one manually.    

My queries are -

  1. why I am not able to create a superuser from command line of my virtual env? In that I am getting a message like this -

    raise ImproperlyConfigured("settings.DATABASES is improperly configured. " django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.

A bit weird considering makemigrations command is working fine.

And when I echo $DJANGO_SETTINGS_MODULE, i get the right setting

appname.settings

Let me know where I am going wrong in create superuser thing?

nishith83
  • 51
  • 1
  • 3
  • I think is because of the name of the function you can see here https://realpython.com/deploying-a-django-app-and-postgresql-to-aws-elastic-beanstalk/#configuring-a-database that the author uses createsu, he doesn't say why but i think this is relatedb – Luiz Oct 26 '21 at 12:56

6 Answers6

8

I solved this problem recently with one of my sample app deployment in beanstalk. I mostly followed the official documentation from this link

  1. In your django app folder create python package 'management'
  2. create another package inside management package 'commands'
  3. create a python file in commands package mysuperuser.py

    import os
    from django.core.management.base import BaseCommand
    from django.contrib.auth.models import User
    
    class Command(BaseCommand):
        def handle(self, *args, **options):
            if not User.objects.filter(username='myuser').exists():
                User.objects.create_superuser('myuser',
                                              'myuser@myemail.com',
                                              'mypassword')
    
  4. In your django-migrate.config file, add a second command

    02_create_superuser_for_django_admin: command: "python manage.py mysuperuser" leader_only: true

  5. do python manage.py collectstatic and eb deploy.

Doing this created the superuser for me.I didn't have to add any PYTHONPATH as described in some answers available online.

  • According to [this](https://stackoverflow.com/a/26091252/9696311), would use get_user_model instead. – jimmy Nov 17 '21 at 03:06
  • 1
    Also, was getting an error during `eb deploy` that django module couldn't be found (in `cfn-init-cmd.log`). I modified the container_command to instead say `"source /var/app/venv/*/bin/activate && python3 manage.py mysuperuser"` which did the trick. – jimmy Nov 17 '21 at 03:07
2

Your custom file is named "createsuperuser.py" that's the same as the Django command, and that collision is what's causing the issue. Use "createsu.py" for the file name, then be sure to change the config file to also use "createsu."

thrillhouse
  • 131
  • 1
  • 7
  • I found the answer and edited my original comment. I find it a little odd that I can answer without rep but can't comment! I so rarely have the answers to questions on here, but here I just wanted to message the original poster of the question and see if he ever found an answer. I guess it's just a quirk of stackoverflow that I have yet to figure out. – thrillhouse Nov 10 '18 at 02:35
2

I spent ages working out how to do this and this is by far the simplest & most secure way. Create the following file .platform > hooks > postdeploy > 01_migrate.sh and input the below:

#!/bin/bash

source /var/app/venv/*/bin/activate && { python migrate.py createsuperuser --noinput; }

You can then add DJANGO_SUPERUSER_PASSWORD, DJANGO_SUPERUSER_USERNAME, DJANGO_SUPERUSER_EMAIL to the configuration section of the application environment and it will know these are to be used as we have specified --noinput.

Then add the below to the folder .ebextentions > django.config . This just gets round permission issues in running 01_migrate.sh

container_commands:
    01_chmod1:
         command: "chmod +x .platform/hooks/postdeploy/01_migrate.sh"

That will create your superuser in a secure way, with the same logic you can also run migrations and collect static by adding to the 01_migrate.sh file.

Chalist
  • 3,160
  • 5
  • 39
  • 68
jimbo
  • 21
  • 1
1

I have a slightly simpler version of @jimbo's answer. Inside .ebextensions/db-migrate.config I have the following:

container_commands:
  01_migrate:
    command: "source /var/app/venv/*/bin/activate && python3 manage.py migrate"
    leader_only: true
  02_createsuperuser:
    command: "source /var/app/venv/*/bin/activate && python3 manage.py createsuperuser --noinput"
    leader_only: true
option_settings:
  aws:elasticbeanstalk:application:environment:
    DJANGO_SETTINGS_MODULE: <appname>.settings

The key lines there are the 02_createsuperuser container command. Once you've got that, you can set the DJANGO_SUPERUSER_PASSWORD, DJANGO_SUPERUSER_USERNAME, DJANGO_SUPERUSER_EMAIL environment variables in the environment and deploy and you'll be good to go. Once you've got the user created, remove that container command so it's not run again with the next deployment.

Ryan
  • 888
  • 1
  • 11
  • 29
1

deepesh and jimbos combined solution did it for me.
It is particularly useful if you have a custom User.
I will write down the steps.

1 Create the command file under management/command. Don't name it createsuperuser.py to avoid conflict.

└-- App_dir
    └-- management
        |-- __init__.py
        └-- commands
            |-- __init__.py
            └-- createsu.py 

2 The command file should look like this.

import os
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand


class Command(BaseCommand):
    help = "Creates a superuser."

    def handle(self, *args, **options):
        if not User.objects.filter(username="username").exists():
            password = os.environ.get("SUPERUSER_PASSWORD")
            if password is None:
                raise ValueError("Password not found")
            User.objects.create_superuser(
                username="username",
                email="email", 
                password=password,
            )
            print("Superuser has been created.")
        else:
            print("Superuser exists")

3 Add the command in the config (inside .ebextension) file.

container_commands:
...
  03_superuser:
    command: "source /var/app/venv/*/bin/activate && python3 manage.py createsu"
    leader_only: true

4 Add the SUPERUSER_PASSWORD in environment > configuration > Software > Environment properties

5 Commit and eb deploy.

We are still storing raw passwords, which isnt the most secure thing in the world. However its much safer than hardcoding the password in the command file.

Julkar9
  • 1,508
  • 1
  • 12
  • 24
-3

You can't use create superuser in a situation where the user can't input the info. See https://realpython.com/blog/python/deploying-a-django-app-to-aws-elastic-beanstalk/#Create.the.Admin.User for a different approach.

UmAnusorn
  • 10,420
  • 10
  • 72
  • 100