summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorNick Pope <nick.pope@flightdataservices.com>2021-01-13 16:19:22 +0000
committerGitHub <noreply@github.com>2021-01-13 17:19:22 +0100
commit920448539631b52dcee53bd32a880abbc9de18bd (patch)
tree03dd52fd206088302de11e0b485b420726718a4a /django
parent83fcfc9ec8610540948815e127101f1206562ead (diff)
Fixed #16117 -- Added decorators for admin action and display functions.
Refs #25134, #32099.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/admin/__init__.py10
-rw-r--r--django/contrib/admin/actions.py9
-rw-r--r--django/contrib/admin/decorators.py73
-rw-r--r--django/contrib/admin/options.py3
4 files changed, 85 insertions, 10 deletions
diff --git a/django/contrib/admin/__init__.py b/django/contrib/admin/__init__.py
index 0bcee1a578..975cf053aa 100644
--- a/django/contrib/admin/__init__.py
+++ b/django/contrib/admin/__init__.py
@@ -1,4 +1,4 @@
-from django.contrib.admin.decorators import register
+from django.contrib.admin.decorators import action, display, register
from django.contrib.admin.filters import (
AllValuesFieldListFilter, BooleanFieldListFilter, ChoicesFieldListFilter,
DateFieldListFilter, EmptyFieldListFilter, FieldListFilter, ListFilter,
@@ -11,10 +11,10 @@ from django.contrib.admin.sites import AdminSite, site
from django.utils.module_loading import autodiscover_modules
__all__ = [
- "register", "ModelAdmin", "HORIZONTAL", "VERTICAL", "StackedInline",
- "TabularInline", "AdminSite", "site", "ListFilter", "SimpleListFilter",
- "FieldListFilter", "BooleanFieldListFilter", "RelatedFieldListFilter",
- "ChoicesFieldListFilter", "DateFieldListFilter",
+ "action", "display", "register", "ModelAdmin", "HORIZONTAL", "VERTICAL",
+ "StackedInline", "TabularInline", "AdminSite", "site", "ListFilter",
+ "SimpleListFilter", "FieldListFilter", "BooleanFieldListFilter",
+ "RelatedFieldListFilter", "ChoicesFieldListFilter", "DateFieldListFilter",
"AllValuesFieldListFilter", "EmptyFieldListFilter",
"RelatedOnlyFieldListFilter", "autodiscover",
]
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
index 1e1c3bd384..665d83c7f7 100644
--- a/django/contrib/admin/actions.py
+++ b/django/contrib/admin/actions.py
@@ -4,12 +4,17 @@ Built-in, globally-available admin actions.
from django.contrib import messages
from django.contrib.admin import helpers
+from django.contrib.admin.decorators import action
from django.contrib.admin.utils import model_ngettext
from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse
from django.utils.translation import gettext as _, gettext_lazy
+@action(
+ permissions=['delete'],
+ description=gettext_lazy('Delete selected %(verbose_name_plural)s'),
+)
def delete_selected(modeladmin, request, queryset):
"""
Default action which deletes the selected objects.
@@ -73,7 +78,3 @@ def delete_selected(modeladmin, request, queryset):
"admin/%s/delete_selected_confirmation.html" % app_label,
"admin/delete_selected_confirmation.html"
], context)
-
-
-delete_selected.allowed_permissions = ('delete',)
-delete_selected.short_description = gettext_lazy("Delete selected %(verbose_name_plural)s")
diff --git a/django/contrib/admin/decorators.py b/django/contrib/admin/decorators.py
index 1c43c9505c..4de99580ad 100644
--- a/django/contrib/admin/decorators.py
+++ b/django/contrib/admin/decorators.py
@@ -1,3 +1,76 @@
+def action(function=None, *, permissions=None, description=None):
+ """
+ Conveniently add attributes to an action function::
+
+ @admin.action(
+ permissions=['publish'],
+ description='Mark selected stories as published',
+ )
+ def make_published(self, request, queryset):
+ queryset.update(status='p')
+
+ This is equivalent to setting some attributes (with the original, longer
+ names) on the function directly::
+
+ def make_published(self, request, queryset):
+ queryset.update(status='p')
+ make_published.allowed_permissions = ['publish']
+ make_published.short_description = 'Mark selected stories as published'
+ """
+ def decorator(func):
+ if permissions is not None:
+ func.allowed_permissions = permissions
+ if description is not None:
+ func.short_description = description
+ return func
+ if function is None:
+ return decorator
+ else:
+ return decorator(function)
+
+
+def display(function=None, *, boolean=None, ordering=None, description=None, empty_value=None):
+ """
+ Conveniently add attributes to a display function::
+
+ @admin.display(
+ boolean=True,
+ ordering='-publish_date',
+ description='Is Published?',
+ )
+ def is_published(self, obj):
+ return obj.publish_date is not None
+
+ This is equivalent to setting some attributes (with the original, longer
+ names) on the function directly::
+
+ def is_published(self, obj):
+ return obj.publish_date is not None
+ is_published.boolean = True
+ is_published.admin_order_field = '-publish_date'
+ is_published.short_description = 'Is Published?'
+ """
+ def decorator(func):
+ if boolean is not None and empty_value is not None:
+ raise ValueError(
+ 'The boolean and empty_value arguments to the @display '
+ 'decorator are mutually exclusive.'
+ )
+ if boolean is not None:
+ func.boolean = boolean
+ if ordering is not None:
+ func.admin_order_field = ordering
+ if description is not None:
+ func.short_description = description
+ if empty_value is not None:
+ func.empty_value_display = empty_value
+ return func
+ if function is None:
+ return decorator
+ else:
+ return decorator(function)
+
+
def register(*models, site=None):
"""
Register the given model(s) classes and wrapped ModelAdmin class with
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 5214a266e3..6b0982eab8 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -12,6 +12,7 @@ from django.contrib.admin import helpers, widgets
from django.contrib.admin.checks import (
BaseModelAdminChecks, InlineModelAdminChecks, ModelAdminChecks,
)
+from django.contrib.admin.decorators import display
from django.contrib.admin.exceptions import DisallowedModelAdminToField
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.contrib.admin.utils import (
@@ -848,12 +849,12 @@ class ModelAdmin(BaseModelAdmin):
action_flag=DELETION,
)
+ @display(description=mark_safe('<input type="checkbox" id="action-toggle">'))
def action_checkbox(self, obj):
"""
A list_display column containing a checkbox widget.
"""
return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, str(obj.pk))
- action_checkbox.short_description = mark_safe('<input type="checkbox" id="action-toggle">')
@staticmethod
def _get_action_description(func, name):