Last active
March 18, 2020 07:56
-
-
Save mark-mishyn/d652a591577aabd53a0a7436cebf2b86 to your computer and use it in GitHub Desktop.
Run Django management command with real-time output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| This example shows how to run Django management command from some of your Django apps. | |
| Stdout and stderr are redirected to Django's StreamingHttpResponse, so | |
| you will see command execution result in realtime. | |
| Example can be easily adopted to run all Django's management commands or | |
| any bash command. | |
| """ | |
| import importlib | |
| import os | |
| import subprocess | |
| from crispy_forms.helper import FormHelper | |
| from crispy_forms.layout import Layout, Submit | |
| from django import forms | |
| from django.apps import apps | |
| from django.contrib.admin.views.decorators import staff_member_required | |
| from django.contrib.auth.decorators import login_required | |
| from django.core.management import find_commands | |
| from django.http import StreamingHttpResponse | |
| from django.shortcuts import render | |
| from django.utils.safestring import mark_safe | |
| from django.views.decorators.http import require_http_methods | |
| COMMANDS_APPS = ['app1', 'app2'] | |
| class RunManagementCommandForm(forms.Form): | |
| command = forms.ChoiceField(choices=[]) | |
| arguments = forms.CharField(required=False) | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| self.fields['command'].choices = list(self.get_commands_list()) | |
| self.helper = FormHelper() | |
| self.helper.form_show_errors = True | |
| self.helper.form_action = 'run_management_command' | |
| self.helper.layout = Layout( | |
| 'command', | |
| 'arguments', | |
| Submit('run command', 'run command', css_class='btn-primary') | |
| ) | |
| @staticmethod | |
| def get_commands_list(): | |
| for app_config in list(apps.get_app_configs()): | |
| if app_config.name in COMMANDS_APPS: | |
| path = os.path.join(app_config.path, 'management') | |
| for command in find_commands(path): | |
| command_class = getattr( | |
| importlib.import_module(app_config.name + '.management.commands.' + command), | |
| 'Command') | |
| yield (command, mark_safe('{} ({})'.format(command, command_class.help))) | |
| def run_command(command): | |
| process = subprocess.Popen( | |
| [command], | |
| shell=True, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| ) | |
| yield b'Start %b!<br/>\n' % command.encode('utf-8') | |
| for std in ['stdout', 'stderr']: | |
| for line in iter(getattr(getattr(process, std), 'readline'), b''): | |
| try: | |
| yield line.rstrip() + b'<br/>\n' | |
| except KeyboardInterrupt: | |
| return | |
| @login_required | |
| @staff_member_required | |
| @require_http_methods(['GET', 'POST']) | |
| def run_management_command(request): | |
| if request.method == 'POST': | |
| form = RunManagementCommandForm(request.POST) | |
| if form.is_valid(): | |
| command = 'python3 manage.py {}'.format(form.cleaned_data['command']) | |
| arguments = form.cleaned_data.get('arguments') | |
| if arguments: | |
| command += ' ' + arguments | |
| return StreamingHttpResponse(run_command(command)) | |
| else: | |
| form = RunManagementCommandForm() | |
| return render(request, 'run_management_command.html', {'form': form}) | |
| """ | |
| and only 2 lines in template | |
| {% load crispy_forms_tags %} | |
| {% crispy form %} | |
| """ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment