diff --git a/django/contrib/admin/decorators.py b/django/contrib/admin/decorators.py
index d3ff56a59a..ad34df2e65 100644
|
a
|
b
|
|
| 1 | | def action(function=None, *, permissions=None, description=None): |
| | 1 | def action(function=None, *, permissions=None, description=None, group=None): |
| 2 | 2 | """ |
| 3 | 3 | Conveniently add attributes to an action function:: |
| 4 | 4 | |
| … |
… |
def action(function=None, *, permissions=None, description=None):
|
| 23 | 23 | func.allowed_permissions = permissions |
| 24 | 24 | if description is not None: |
| 25 | 25 | func.short_description = description |
| | 26 | if group is not None: |
| | 27 | func.action_group = group |
| 26 | 28 | return func |
| 27 | 29 | |
| 28 | 30 | if function is None: |
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 8ccacd6213..ca61901fe7 100644
|
a
|
b
|
|
| 1 | 1 | import copy |
| | 2 | from collections import defaultdict |
| 2 | 3 | import json |
| 3 | 4 | import re |
| 4 | 5 | from functools import partial, update_wrapper |
| … |
… |
class ModelAdmin(BaseModelAdmin):
|
| 1024 | 1025 | Return a list of choices for use in a form object. Each choice is a |
| 1025 | 1026 | tuple (name, description). |
| 1026 | 1027 | """ |
| | 1028 | choices = defaultdict(list) |
| | 1029 | choices[None].extend(default_choices) |
| 1027 | 1030 | choices = [] + default_choices |
| 1028 | 1031 | for func, name, description in self.get_actions(request).values(): |
| 1029 | 1032 | choice = (name, description % model_format_dict(self.opts)) |
| 1030 | | choices.append(choice) |
| 1031 | | return choices |
| | 1033 | choices[getattr(func, 'action_group', None)].append(choice) |
| | 1034 | return list(choices.items()) |
| 1032 | 1035 | |
| 1033 | 1036 | def get_action(self, action): |
| 1034 | 1037 | """ |