장고 manage.py에 사용자 지정 커맨드를 만들어 사용할 수 있다.커스텀 커맨드를 작성하는 것으로 manage.py부터 사용할 수 있는 커맨드를 늘릴 수가 있다.
지금부터 원하는 기능을 커맨드로 만들어서 사용하여 보자.
Django 커스텀 커맨드는 Django에서 생성하는 앱마다 만들 수 있으며, 커스텀 하여 만들어진 커맨드는 manage.py에서 실행할 수 있다.
예를 들어 내가 showuser
라는 커맨드를 만들면 아래와 같이 사용할 수 있게된다.
python3 manage.py showuser
Django에서 관리용으로 모델을 조작하거나 참조하고 싶을 경우, 뷰를 일부러 정의하여 브라우저로 부터 실행하는 것은 매우 번거롭고, 귀찮은 일이다.
그러나 커스텀 커맨드를 만들면 커맨드 라인에서 모델, 나아가서는 전체 프로젝트를 참조 할 수 있어 매우 편리해진다.
💡 커스텀 커맨드를 만드는 cron등의 스케줄러와 조합하면 정기적으로 프로젝트를 변경하는 시스템도 구축할 수 있다.
Django 커스텀 커맨드는 설치한 앱 하위에 management라는 디렉토리를 만들고 그 아래 commands라는 디렉토리를 만든다. 그리고 커맨드명에 해당하는 모듈을 배치하고, 모듈 안에서 커맨드의 클래스를 만드는 것으로 Django가 그 커맨드를 인식한다.
% python3 manage.py
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
[auth]
changepassword
createsuperuser
[contenttypes]
remove_stale_contenttypes
[debug_toolbar]
debugsqlshell
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
위의 manage.py로 커맨드를 입력하면 현재 사용할 수 있는 명령어를 확인할 수 있다.
아래와 같이 management>commands>showuser.py 파일을 추가 후 동일한 폴더에 __init__.py
파일을 생성 후 다시 한 번 manage.py 명령어를 확인하여 보자.
내가 생성한 showuser라는 명령어를 확인 할 수 있을 것이다.
% python3 manage.py
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
...
[shortener]
showuser
...
커스텀 커맨드를 사용하기 위한 임의의 모델을 생성해 보자.
models.py
class User(models.Model):
''' 커스텀 커맨드를 위한 모델 생성 '''
name = models.CharField(max_length=128, help_text="사용자 이름")
content = models.TextField(max_length=1024, help_text="사용자 설명")
모델을 정의한 후 마이그레이션을 진행한다.
% python3 manage.py makemigrations
% python3 manage.py migrate
커맨드로 실행하는 showuser.py파일 안에 명령어를 작성하여보자.
management>commands>showuser.py
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Show user list'
def handle(self, *args, **options):
self.stdout.write('show user')
다음과 같이 Command 라고 하는 클래스를 만들어 준다.
이 클래스는 BaseCommand 를 상속함으로서 명령어를 이용하여 실행할 수 있게 된다.
help 속성에 커맨드의 설명을 작성하면 -h 옵션사용 시 그에 대한 설명을 확인 할 수 있다.
handle() 메소드 를 오버라이드(override)해, 커맨드가 실행되었을 때의 처리를 기입하게 한다.
% python3 manage.py showuser
show user
% python3 manage.py showuser -h
usage: manage.py showuser [-h] [--version] [-v {0,1,2,3}] [--settings SETTINGS]
[--pythonpath PYTHONPATH] [--traceback] [--no-color]
[--force-color] [--skip-checks]
Show user list
options:
-h, --help show this help message and exit
--version Show program's version number and exit.
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions.
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
--skip-checks Skip system checks.
커맨드를 실행하게 되면 본인이 작성한 코드가 실행되며 -h 옵션을 붙여 커맨드를 실행하게 되면 help 변수에 작성해 놓았던 커맨드의 설명이 출력되는 것을 확인 할 수 있다.
커맨드에서 표준 출력과 표준 에러를 사용하려면 self.stdout과 self.stderr를 사용하는 것이 추천되고 있다.
이러한 파일 객체를 사용하면 커맨드를 테스트하고 디버깅할 수 있다.
def handle(self, *args, **options):
self.stdout.write('success')
self.stderr.write('error')
또, 이러한 오브젝트의 wirte()메소드는 개행을 자동으로 부가한다. 따라서 개발자가 줄 끝에 줄 바꿈을 추가 할 필요가 없다.
개행을 제거하고 싶은 경우 print()메소드에서 사용하는 것과 동일하게 ending인수에 공문자열을 지정하면된다.
def handle(self, *args, **options):
self.stdout.write('success', ending='')
self.stderr.write('error', ending='')
커맨드는 기본적으로 인수를 사용하지 않는다. 하지만 커맨드가 인수가 필요한 경우 추가하여 커맨드를 사용할 수 있다.
from django.core.management.base import BaseCommand
from shortener.models import User
class Command(BaseCommand):
help = 'Create user data'
def add_arguments(self, parser):
parser.add_argument('attrs', nargs='+', type=str)
def handle(self, *args, **options):
attrs = options['attrs']
user = User.objects.create(name=attrs[0], content=attrs[1])
self.stdout.write('Complete created user')
위와 다르게 add_arguments() 메소드가 추가되었다. 이 메소드의 parser매개변수를 이용하여
parser.add_argument를 사용하면 커맨드로 전달할 인자를 받아 handle()메소드로 전달시켜 준다.
handle() 메소드에서는 위에서 전달한 인자를 options 매개변수로 전달받아 사용자를 생성하는 데이터 처리를 진행한다.
% python3 manage.py createuser username usercontent
['username', 'usercontent']
username usercontent
Complete created user
추가로 생성한 데이터를 지워주기 위해 삭제 커맨드를 작성해 보았다.
from django.core.management.base import BaseCommand
from shortener.models import User
class Command(BaseCommand):
help = 'Delete user data'
def add_arguments(self, parser):
parser.add_argument('user_id', nargs='+', type=str)
def handle(self, *args, **options):
users = options['user_id']
print(users)
for user_id in users:
user = User.objects.filter(id=str(user_id)).last()
user.delete()
% python3 manage.py deleteuser 3
['3']
delete user 3
인수가 아닌 옵션을 통해 인자를 전달하여 명령어를 실행해보자.
from django.core.management.base import BaseCommand
from shortener.models import User
class Command(BaseCommand):
help = 'Create user data'
def add_arguments(self, parser):
# parser.add_argument('attrs', nargs='+', type=str)
parser.add_argument('-n', '--name', required=True, type=str)
parser.add_argument('-c', '--content', required=True, type=str)
def handle(self, *args, **options):
# attrs = options['attrs']
attrs = [options['name'], options['content']]
user = User.objects.create(name=attrs[0], content=attrs[1])
self.stdout.write('Complete created user')
% python3 manage.py createuser -n username -c usercontent
% python3 manage.py createuser --name username2 --content usercontent2
['username', 'usercontent']
Complete created user
['username2', 'usercontent2']
Complete created user