diff --git a/.gitignore b/.gitignore index 3afb01e..0d8962c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ *.pyc *~ -example/db.sqlite \ No newline at end of file +example/db.sqlite +django_admincommand.egg-info +.ropeproject +build/ +dist/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..0f46a76 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include README.rst + +recursive-include admincommand/templates * diff --git a/README.rst b/README.rst index e2ac7dc..d00036d 100644 --- a/README.rst +++ b/README.rst @@ -46,7 +46,7 @@ Then you will have to create a configuration class for the command:: # ./music/admincommands.py - from admincommands.models import AdminCommand + from admincommand.models import AdminCommand class Lyrics(AdminCommand): @@ -57,6 +57,8 @@ Then you will have to create a configuration class for the command:: def get_command_arguments(self, forms_data): return [forms_data['title']], {} +*NOTE*: This all works based on naming conventions. The file with the form must be called `admincommands` and the form class name must be the same as the management command file name (with camel case converted to underscore notation). + And all is well, the new admin command will be available under the «Admin Command» area of the administration of the default admin site. diff --git a/admincommand/admin.py b/admincommand/admin.py index 5d124a7..34d75e8 100644 --- a/admincommand/admin.py +++ b/admincommand/admin.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- +from functools import update_wrapper + from django.contrib import admin from django.shortcuts import render from django.contrib.admin.options import csrf_protect_m -from django.http import HttpResponse, HttpResponseRedirect -from django.shortcuts import redirect -from django.conf.urls.defaults import url +from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse -from django.http import HttpResponseBadRequest -from django.conf.urls.defaults import patterns -from django.utils.encoding import force_unicode -from django.utils.functional import update_wrapper +from django.conf.urls import url +from django.utils.encoding import force_text from django.http import HttpResponseForbidden from django.utils.safestring import mark_safe from django.contrib import messages @@ -25,9 +23,9 @@ class AdminCommandAdmin(SneakAdmin): list_display = ('command_name',) - def queryset(self, request): + def get_queryset(self, request): # user current user to construct the queryset - # so that only commands the user can execute + # so that only commands the user can execute # will be visible return CommandQuerySet(request.user) @@ -37,13 +35,12 @@ def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) - urlpatterns = patterns( - '', + urlpatterns = [ url( r'^run/([\w_]+)', wrap(self.run_command_view), ) - ) + ] return urlpatterns + super(AdminCommandAdmin, self).get_urls() def run_command_view(self, request, url_name): @@ -60,7 +57,7 @@ def run_command_view(self, request, url_name): ctx = { # original needed ``change_form.html`` context variables - 'module_name': force_unicode(opts.verbose_name_plural), + 'module_name': force_text(opts.verbose_name_plural), 'title': admin_command.name(), 'is_popup': False, 'root_path': None, diff --git a/admincommand/core.py b/admincommand/core.py index 568d993..e9698f2 100644 --- a/admincommand/core.py +++ b/admincommand/core.py @@ -1,18 +1,22 @@ -from StringIO import StringIO +from six import StringIO + +from importlib import import_module from django.conf import settings from django.core import management from django.core.management import get_commands from django.core.management import load_command_class -from django.utils.importlib import import_module from django.core.management.base import BaseCommand from django.contrib.auth.models import User -from async import schedule +try: + from async import schedule +except ImportError: + schedule = None from admincommand.models import AdminCommand -# Cache variable to store runnable commands configuration +# Cache variable to store runnable commands configuration _command_configs = {} @@ -57,12 +61,15 @@ def call_command(command_name, user_pk, args=None, kwargs=None): management.call_command(command_name, *args, **kwargs) return output.getvalue() + def run_command(command_config, cleaned_data, user): if hasattr(command_config, 'get_command_arguments'): - args, kwargs = command_config.get_command_arguments(cleaned_data) + args, kwargs = command_config.get_command_arguments(cleaned_data, user) else: args, kwargs = list(), dict() if command_config.asynchronous: + if not callable(schedule): + return 'This task is asynchronous but django-async is not installed' task = schedule(call_command, [command_config.command_name(), user.pk, args, kwargs]) return task else: diff --git a/admincommand/management.py b/admincommand/management.py index 3e4d8f0..725d7b7 100644 --- a/admincommand/management.py +++ b/admincommand/management.py @@ -1,8 +1,10 @@ +from importlib import import_module + +import django from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Permission from django.db.models import signals -from django.utils.importlib import import_module import admincommand @@ -31,4 +33,8 @@ def sync_db_callback(verbosity=0, interactive=False, signal=None, **kwargs): content_type=ct, name='Can run %s' % subclass.command_name(), ) -signals.post_syncdb.connect(sync_db_callback, sender=admincommand.models) + +if django.VERSION >= (1, 7): + signals.post_migrate.connect(sync_db_callback, sender=admincommand.models) +else: + signals.post_syncdb.connect(sync_db_callback, sender=admincommand.models) diff --git a/admincommand/migrations/0001_initial.py b/admincommand/migrations/0001_initial.py new file mode 100644 index 0000000..400c509 --- /dev/null +++ b/admincommand/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AdminCommand', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/example/__init__.py b/admincommand/migrations/__init__.py similarity index 100% rename from example/__init__.py rename to admincommand/migrations/__init__.py diff --git a/admincommand/models.py b/admincommand/models.py index 50443b3..1d5e765 100644 --- a/admincommand/models.py +++ b/admincommand/models.py @@ -33,7 +33,7 @@ def get_help(self): def command(self): """Getter of the management command import core""" - import core + from . import core command = core.get_command(self.command_name()) return command @@ -53,6 +53,6 @@ def permission_codename(cls): @classmethod def all(cls): - import core + from . import core for runnable_command in core.get_admin_commands().values(): yield runnable_command diff --git a/admincommand/templates/admincommand/output.html b/admincommand/templates/admincommand/output.html index 8f350dc..f91507e 100644 --- a/admincommand/templates/admincommand/output.html +++ b/admincommand/templates/admincommand/output.html @@ -1,11 +1,7 @@ {% extends "admin/change_form.html" %} -{% load i18n %} -{% block extrahead %} - {{ block.super }} - -{% endblock %} +{% load i18n %} {% block breadcrumbs %}