Skip to content

Instantly share code, notes, and snippets.

@mark-mishyn
Last active March 18, 2020 07:56
Show Gist options
  • Select an option

  • Save mark-mishyn/d652a591577aabd53a0a7436cebf2b86 to your computer and use it in GitHub Desktop.

Select an option

Save mark-mishyn/d652a591577aabd53a0a7436cebf2b86 to your computer and use it in GitHub Desktop.
Run Django management command with real-time output
"""
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