大虾居

谈笑有鸿儒,往来无白丁。

0%

给Django应用增加一个初始化admin管理员用户的命令行工具

为什么要添加一个初始化超级用户的命令行入口

django提供了一系列重要而且好用的命令行工具,使用创建项目时自动生成的manage.py,
或者全局django-admin都可以运行这些程序。

python mamage.py

django-admin

其中在启用了django.contrib.authapp之后,我们可以受用createsuperuser命令来创建超级用户。

python manage.py createsuperuser

这个命令通常时我们启用django身份验证功能之后要登录到admin站点必须要使用的命令。但是这个命令的
问题在于它只能用交互方式运行,我们无法用一个非交互式脚本来创建用户,比如我们的站点需要一键
安装、自动化搭建测试环境等等场景。

在使用命令行之外我们也有其他选项,比如在migrations增加一个创建默认超级用户的脚本,在安装过程中
执行migrate从而添加默认超级用户。但这样做的问题是默认用户信息在所有环境中都是相同的,如果管理人员
忘记修改默认密码,可能会导致安全风险。

如果有一个命令行能用无交互的方式,使用参数来指定超级用户的账号和密码,就会适应更多场景的要求。

如何实现

命令行接口的设计

我们需要一个命令行工具,用如下的方式创建一个超级用户。

python manage.py initadmin --user=admin --password=YourPassword --email=abc@example.com

这个命令行还能从环境变量中读取参数信息

DJANGO_SU_NAME=admin DJANGO_SU_PASSWORD=YourPassword DJANGO_SU_EMAIL=abc@example.com python manage.py initadmin 

或者

export DJANGO_SU_NAME=admin
export DJANGO_SU_PASSWORD=YourPassword
export DJANGO_SU_EMAIL=abc@example.com
python manage.py initadmin 

使用django custom django-admin commands框架

django提供了自行扩展命令行工具的框架,添加相关代码后可以直接采用manage.py或python-admin命令行进行调用。
相关文档可以参考!()[https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/]

首先需要在自己的app中创建指定文件夹,django会从指定文件夹中加载相应模块,假设你的app名字为myapp,
command模块应在myapp/management/commands文件夹下,
这两个文件夹都是package,因此别忘了在management文件夹和commands文件夹都添加__init__.py文件,

commands 包下添加initadmin模块,即initadmin.py

# myapp/management/commands/initadmin.py
import os
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User


class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('--user')
        parser.add_argument('--password')
        parser.add_argument('--email')

    def handle(self, *args, **options):
        admin_username = options.get('user') or os.environ.get('DJANGO_SU_NAME')
        admin_email = options.get('email') or os.environ.get('DJANGO_SU_EMAIL')
        admin_password = options.get('password') or os.environ.get('DJANGO_SU_PASSWORD')

        if not admin_username:
            raise Exception("No username specified.")

        if not admin_email:
            raise Exception('No email specified.')

        if not admin_password:
            raise Exception('No password specified.')

        if User.objects.filter(username=admin_username).first():
            print(f'{admin_username} user already exists.')
            return

        admin_user = User.objects.create_superuser(username=admin_username,
                                                   email=admin_email,
                                                   password=admin_password)
        admin_user.is_active = True
        admin_user.is_admin = True
        admin_user.save()
        print(f'{admin_username} user created.')

使用

命令行使用

如前面提到的方式使用即可,可通过命令行参数指定admin用户信息,或者使用环境变量

DJANGO_SU_NAME=admin DJANGO_SU_PASSWORD=YourPassword DJANGO_SU_EMAIL=abc@example.com python manage.py initadmin 

DJANGO_SU_NAME=admin DJANGO_SU_PASSWORD=YourPassword DJANGO_SU_EMAIL=abc@example.com python manage.py initadmin 

在docker中使用

首先在entrypoint.sh 中增加检查选项,并根据选项运行命令行

# docker-entrypoint.sh
if [ "x$DJANGO_MANAGEPY_INITADMIN" = 'xon' ]; then
  $PYTHON manage.py initadmin
fi

在docker运行时指定参数

docker run -e DJANGO_MANAGEPY_INITADMIN=on -e DJANGO_SU_NAME=admin -e DJANGO_SU_PASSWORD=YourPassword xxx

或者在docker-compose中指定参数

#docker-compose.yml
version: '3'
services:
  web:
    image: xxx
    ports:
      - "8000:8000"
    environment:
      DJANGO_MANAGEPY_INITADMIN: 'on'
      DJANGO_SU_NAME: 'admin'
      DJANGO_SU_PASSWORD: 'YourPassword'