可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am tring to createsuperuser in a django docker container with fabric.
To create the super user in django, I need run this in a django interactive mode:
./manage.py createsuperuser
And because I want to make it run in a fabric script, so I find this command could avoid inputing password
echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | ./manage.py shell
Then I put this together with "docker exec" to run it in my django container
docker exec container_django echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | ./manage.py shell
The problem comes out with the linux pipe, the pipe(|) all the contents on its left(including the docker exec) to its right(./manage.py shell)
And this is not only difficult part, considering to put all these junks into a fabric run, which means they need quotes on both end. It will make whole thing very urgly.
fabric run:
run("docker exec container_django {command to create django super user}")
I am still struggling on how to make at least the junk work in a fabric run, but I don't know how to do it.
回答1:
I handle this by evaluating the python code line in Dockerfile.
ENV DJANGO_DB_NAME=default
ENV DJANGO_SU_NAME=admin
ENV DJANGO_SU_EMAIL=admin@my.company
ENV DJANGO_SU_PASSWORD=mypass
RUN python -c "import django; django.setup(); \
from django.contrib.auth.management.commands.createsuperuser import get_user_model; \
get_user_model()._default_manager.db_manager('$DJANGO_DB_NAME').create_superuser( \
username='$DJANGO_SU_NAME', \
email='$DJANGO_SU_EMAIL', \
password='$DJANGO_SU_PASSWORD')"
Note that this is different from calling
User.objects.create_superuser('admin', 'admin@example.com', 'pass')
as django.contrib.auth.get_user_model
will work fine with custom user model if you should have any (which is quite common), while with User.objects.create
you only create a standard user entity, ignoring any custom user model.
Also, it's the same call that django's createsuperuser
command does under the hood, so it should be pretty safe to do.
回答2:
I recommend adding a new management command that will automatically create a superuser if no Users exist.
See small example I created at https://github.com/dkarchmer/aws-eb-docker-django. In particular, see how I have a python manage.py initadmin
which runs:
class Command(BaseCommand):
def handle(self, *args, **options):
if Account.objects.count() == 0:
for user in settings.ADMINS:
username = user[0].replace(' ', '')
email = user[1]
password = 'admin'
print('Creating account for %s (%s)' % (username, email))
admin = Account.objects.create_superuser(email=email, username=username, password=password)
admin.is_active = True
admin.is_admin = True
admin.save()
else:
print('Admin accounts can only be initialized if no Accounts exist')
(See Authentication/management/commands).
You can see how the Dockerfile then just runs CMD to runserver.sh which basically runs
python manage.py migrate --noinput
python manage.py initadmin
python manage.py runserver 0.0.0.0:8080
Obviously, this assumes the Admins immediately go change their passwords after the server is up. That may or may not be good enough for you.
回答3:
Get the container ID and run the command.
docker exec -it container_id python manage.py createsuperuser
回答4:
Might be easiest to just put together a Python script to create the Django superuser for you, instead of trying to feed all those commands through manage.py shell
. Can you put your commands in a .py file, let's say yourfile.py
:
#!/usr/bin/env python
from django.contrib.auth.models import User
User.objects.create_superuser('admin', 'admin@example.com', 'pass')
And then, after doing chmod +x yourfile.py
:
fabric run:
run("docker exec container_django yourfile.py")
Depending on your setup you may need to make sure that the DJANGO_SETTINGS_MODULE
environment variable is set appropriately for that run() command.
回答5:
I took @hoefling's answer, and changed it a little.
I needed to create super user AFTER the build step. So i put it inside a supervisor script. That means it will be executed every time i run the container. So i added a simple if / else control to check if superuser is already created. That reduces the execution time. And we need to set DJANGO_SETTINGS_MODULE
environment variable as well.
python -c "import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'project_name.settings'
import django
django.setup()
from django.contrib.auth.management.commands.createsuperuser import get_user_model
if get_user_model().objects.filter(username='$DJANGO_SUPERUSER_USERNAME'):
print 'Super user already exists. SKIPPING...'
else:
print 'Creating super user...'
get_user_model()._default_manager.db_manager('$DJANGO_DB_NAME').create_superuser(username='$DJANGO_SUPERUSER_USERNAME', email='$DJANGO_SUPERUSER_EMAIL', password='$DJANGO_SUPERUSER_PASSWORD')
print 'Super user created...'"
回答6:
I would suggest running a Data Migration, so when you startup your Docker services (e.g. app & db) via docker-compose up
, you can execute all migrations exactly once docker-compose exec web python code/manage.py migrate
So your migration would look like this (assuming you store credentials etc. in environment variables)
import os
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('<your_app>', '<previous_migration>'),
]
def generate_superuser(apps, schema_editor):
from django.contrib.auth.models import User
DJANGO_DB_NAME = os.environ.get('DJANGO_DB_NAME', "default")
DJANGO_SU_NAME = os.environ.get('DJANGO_SU_NAME')
DJANGO_SU_EMAIL = os.environ.get('DJANGO_SU_EMAIL')
DJANGO_SU_PASSWORD = os.environ.get('DJANGO_SU_PASSWORD')
superuser = User.objects.create_superuser(
username=DJANGO_SU_NAME,
email=DJANGO_SU_EMAIL,
password=DJANGO_SU_PASSWORD)
superuser.save()
operations = [
migrations.RunPython(generate_superuser),
]
This allows you to use a built container to execute against a database, whether it's a local db in the same container or a separate service. And it's not done every time you rebuild your container, but only when the migration is necessary.