You don't have access to the command-line value when the @deco
decorator is applied, no. But you can delay applying that decorator until you do have access.
Do so by creating your own decorator. A decorator is simply a function that applied when Python parses the @decorator
and def functionname
lines, right after Python created the function object; the return value of the decorator takes the place of the decorated function. What you need to make sure, then, is that your decorator returns a different function that can apply the deco
decorator when the command is being executed.
Here is such a decorator:
from functools import wraps
def apply_deco_from_name(f):
@wraps(f)
def wrapper(self, *args, **options):
# this code is called instead of the decorated method
# and *now* we have access to the options mapping.
name = options["name"] # or use options.pop("name") to remove it
decorated = deco(name)(f) # the same thing as @deco(name) for the function
return decorated(self, *args, **options)
return wrapper
Then use that decorator on your command handler:
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
"--name",
type=str,
required=True,
)
@apply_deco_from_name
def handle(self, *_args, **options):
name = options["name"]
What happens here? When Python handles the @apply_deco_from_name
and def handle(...)
lines, it sees this as a complete function statement inside the class. It'll create a handle
function object, then passes that to the decorator, so it calls apply_deco_from_name(handle)
. The decorator defined above return wrapper
instead.
And when Django then executes the command handler, it will do so by calling that replacement with wrapper(command, [other arguments], name="command-line-value-for-name", [other options])
. At that point the code creates a new decorated version of the handler with decorated = deco("command-line-value-for-name")(f)
just like Python would have done had you used @deco("command-line-value-for-name")
in your command class. deco("command-line-value-for-name")
returns a decorator function, and deco("command-line-value-for-name")(f)
returns a wrapper, and you can call that wrapper at the end.