Change the behavior of a command
Now that we have created multiple commands and projects, we are going to change the behavior of these commands for a specific project. This is where things get really interesting because, you can start to shape your framework as you want in order to fit your needs.
How it works?
Socon works with managers and hooks. You can get more information here.
Commands are hooks of the CommandManager class. It’s
this class that will look for every commands in the management/commands directory
that you have in the common space, your projects and even Socon.
When you start a command, Socon will look for this command in a specific order. The last being the most important:
Socon
Plugins
Common
Projects
Here is an example: Let’s use the build command that we created in the previous
tutorial.
This command is common to all projects. If we don’t redefine this command in one
of the project, the CommandManager will return the command from the
common space.
Now, if we define the build command in the apollo project,
the CommandManager will return that command instead of the one in the
common space.
Change the behavior
To show the behavior described above, let’s add a new argument to the apollo project.
To do that we will take a shortcut and copy the build.py file from the common space
to the apollo project:
$ cp tutorial/management/commands/build.py projects/apollo/management/commands/build.py
If you start the help command using python manage.py help you will
see that apollo has now a command called build:
...
[apollo]
build (P)
If you start the command as usual, you won’t see any difference as it will
basically execute the same code. To change its behavior, instead of subclassing
this class from the ProjectCommand, we will subclass it by the one in the common space.
This way, we use object inheritance and we have an extension of the build command
for the apollo project.
The build.py of apollo:
from argparse import ArgumentParser
from tutorial.management.commands.build import BuildCommand
from socon.core.management.base import Config
from socon.core.registry.base import ProjectConfig
class BuildCommand(BuildCommand):
name = 'build'
def add_arguments(self, parser: ArgumentParser) -> None:
super().add_arguments(parser)
parser.add_argument(
'--info', help='Add info to the handle command'
)
def handle(self, config: Config, project_config: ProjectConfig):
print(config.getoption('info'))
super().handle(config, project_config)
Now you just have to execute the command from the apollo project like this:
$ python manage.py build --project apollo --info "5 Days left"
You should see this result:
5 Days left
Building Saturn IB
Congratulations! You have modified the behavior of the build command! You
can now build any spacecraft you want :)
Note
This also works for general commands. If you declare the same command
in one of your projects you will be able to access it if you add the
--project option to the command. Try it for yourself and change
the behavior of the createcontainer command!