[Django] Command 만들기

오제욱·2023년 7월 26일
0
post-thumbnail

1. Management Command

Django에는 기본적으로 제공하는 command 가 존재한다.

python manage.py runserver
python manage.py makemigrations
python manage.py migrate

위와 같은 command 들이 기본적으로 제공된다.
python manage.py 로 시작하여 우리가 자주 사용하는 기본 명령어들을 Management Command 라고 한다.

우리가 사용하는 command는 manage.py 에 등록되어 사용할 수 있게 되는 것이다.

아래는 실제 python manage.py runserver 명령어 사용시에 실행되는 코드이다.

# django/core/management/commands/runserver.py


import errno
import os
import re
import socket
import sys
from datetime import datetime

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.core.servers.basehttp import (
    WSGIServer, get_internal_wsgi_application, run,
)
from django.utils import autoreload
from django.utils.regex_helper import _lazy_re_compile

naiveip_re = _lazy_re_compile(r"""^(?:
(?P<addr>
    (?P<ipv4>\d{1,3}(?:\.\d{1,3}){3}) |         # IPv4 address
    (?P<ipv6>\[[a-fA-F0-9:]+\]) |               # IPv6 address
    (?P<fqdn>[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*) # FQDN
):)?(?P<port>\d+)$""", re.X)


class Command(BaseCommand):
    help = "Starts a lightweight Web server for development."

    # Validation is called explicitly each time the server is reloaded.
    requires_system_checks = []
    stealth_options = ('shutdown_message',)

    default_addr = '127.0.0.1'
    default_addr_ipv6 = '::1'
    default_port = '8000'
    protocol = 'http'
    server_cls = WSGIServer
	
    ....
    

runserver 명령어는 /django/core/management/commands 폴더에 runserver.py 라는 이름의 파이썬 파일로 정의 되어 있는 내용이 실행 되는 개념이다

이를 통해 기본 제공 되는 Management Command 외에도 필요에 따라 다양한 Command를 생성하여 사용 할 수 있다.

2. Custom Management Command

2-1 app 내부에 파일 생성

Custom Command 를 생성 하기 위해서는 생성한 app 내부에 /management/commands 폴더를 생성하고 해당 폴더 아래에 파이썬 파일을 작성 함으로 Custom Command를 생성할 수 있다.

├── init.py
├── admin.py
├── apps.py
├── management
│   └── commands
│   └── customcommand.py
├── migrations
├── models.py
├── tests.py
└── views.py

폴더와 command 파일을 생성하게 되면 다음과 같은 파일 구조를 가지게 된다.
위의 예시에서는 customcommand 라는 이름으로 파이썬 파일을 생성했고 해당 command 를 실행 할 때는 python manage.py customcommand 라는 명령어로 command를 실행하게 된다.
따라서 custom command 파일의 이름은 실제 사용할 명령어의 이름으로 command의 목적에 맞게 설정하는 것이 좋다.

2-2 command 작성

이번 글에서는 Article 이라는 모델을 사용하여 command를 생성 할 것이고 model 의 내용은 아래와 같다.

from django.db import models
from django.contrib.auth.models import User
from common.models import CommonModel


class Article(CommonModel):

    """Article Model Definition"""

    title = models.CharField(max_length=200)
    content = models.TextField(blank=True)
    writer = models.ForeignKey(
        "auth.User", related_name="articles", on_delete=models.SET_NULL, null=True
    )

    def __str__(self):
        return self.title

CommonModel 에 대한 내용은
[Django] 자주 사용하는 필드 분리
를 참고 하면 된다.

개발 단계에서 테스트를 위해 Article 모델에 데이터를 하나씩 생성하기에는 시간이 걸리고 효율적이지 않기 때문에 개발단계에서 확인할 수 있는 임의의 데이터를 생성 하기위해 Custom Command 를 작성 할 수 있다.

각 유저마다 임의의 글을 생성하는 command 는 아래와 같다.

# articles/management/commands/createarticle.py

from django.core.management import BaseCommand
from django.contrib.auth.models import User
from article.models import Article


# "Command" 라는 class 이름은 고정
class Command(BaseCommand):
	# handle 함수에 command 를 통해 수행할 내용 작성
    def handle(self, *args, **options):
    	# 전체 user 가져오기
        users = User.objects.all()
        for user in users:
            for i in range(1, 6):
            	# article에 들어갈 정보 정의 
                payload = {
                    "title": f"{user.username}{i}번째 글",
                    "content": f"{i}번째 글 내용",
                    "writer": user
                }
                # 글 생성
                article = Article.objects.create(**payload)
                print(f"{article.id} article created.")

		# 전체 성공 완료 메세지
        self.stdout.write(self.style.SUCCESS('Successfully created Article'))

BaseCommand 를 상속 받은 Command 클래스 안에 handle 함수를 오버라이딩 하여 Custom Command를 통해 수행하고 싶은 기능을 정의 하면 된다.

2-3 Command Option 추가

Custom Command의 옵션을 추가 하고 싶을 때는 add_arguments 메소드를 오버라이딩 한다.

from django.core.management import BaseCommand
from django.contrib.auth.models import User
from article.models import Article


class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument(
            "name", type=str, help="article name", default="", nargs="?"
        )

    def handle(self, *args, **options):
        target_name = options.get("name")
        users = User.objects.all()

        if target_name:
            for user in users:
                for i in range(1, 6):
                    payload = {
                        "title": target_name,
                        "content": f"{i}번째 글 내용",
                        "writer": user
                    }
                    article = Article.objects.create(**payload)
                    print(f"{article.id} article created.")
        else:
            for user in users:
                for i in range(1, 6):
                    payload = {
                        "title": f"{user.username}{i}번째 글",
                        "content": f"{i}번째 글 내용",
                        "writer": user
                    }
                    article = Article.objects.create(**payload)
                    print(f"{article.id} article created.")

        self.stdout.write(self.style.SUCCESS('Successfully created Article'))
        

위처럼 add_arguments 를 사용하여 커맨드에 옵션을 부여할 수 있다.
자세히 살펴보면

parser.add_argument(
            "name", type=str, help="article name", default="", nargs="?"
        )
  • 첫번째 인자 : handle 메소드에서 가져올 변수명
  • 두번째 인자 (type) : 옵션의 자료형
  • 세번째 인자 (help) : 커맨드 옵션에 대한 help text
  • 네번째 인자 (default) : 옵션을 입력하지 않았을 때의 default 값
  • 다섯번째 인자 (nargs) : 명령줄에서 인수를 얼마나 많이 가져올지를 지정
    - N : 인수는 정확히 N 개의 값을 가져야 함 ex) nargs=3 면 인수는 3개의 값을 가짐
    - ? : 인수는 단일 값을 가져오거나 값을 가져오지 않을 수 있음, 값이 제공되지 않으면, default 값이 사용
    - * : 인수는 임의의 수의 값을 가져올 수 있습니다. 이것은 'zero or more'을 의미
    - + : 인수는 적어도 하나 이상의 값을 가져야 합니다. 이것은 'one or more을 의미

위처럼 인자를 추가해서 다양한 방법으로 커맨드를 사용 할 수 있다.

Django Command는 다양한 방법으로 사용 될 수 있다. 필요시에 맞춰 사용하게 된다면 반복적인 작업을 줄여주고 효율적으로 사용할 수 있다.

profile
Django Python 개발자

1개의 댓글

comment-user-thumbnail
2023년 7월 26일

글 잘 봤습니다.

답글 달기