是否可以为django管理员创建一个自定义管理操作,不需要选择一些对象来运行它?
如果您尝试在不选择对象的情况下运行操作,则会收到消息:
Items must be selected in order to perform actions on them. No items have been changed.
是否有办法覆盖此行为并让操作仍然运行?
答案 0 :(得分:11)
接受的答案在django 1.6中对我不起作用,所以我最终得到了这个:
from django.contrib import admin
class AdvWebUserAdmin(admin.ModelAdmin):
....
def changelist_view(self, request, extra_context=None):
if 'action' in request.POST and request.POST['action'] == 'your_action_here':
if not request.POST.getlist(admin.ACTION_CHECKBOX_NAME):
post = request.POST.copy()
for u in MyModel.objects.all():
post.update({admin.ACTION_CHECKBOX_NAME: str(u.id)})
request._set_post(post)
return super(AdvWebUserAdmin, self).changelist_view(request, extra_context)
当调用my_action
并且未选择任何内容时,请选择db中的所有MyModel
个实例。
答案 1 :(得分:6)
我想要这个但最终决定不使用它。在此发布以供将来参考。
在操作中添加额外的属性(如acts_on_all
):
def my_action(modeladmin, request, queryset):
pass
my_action.short_description = "Act on all %(verbose_name_plural)s"
my_action.acts_on_all = True
在ModelAdmin
中,覆盖changelist_view
以检查您的财产。
如果请求方法是POST,并且指定了操作,并且操作callable将您的属性设置为True,则修改表示所选对象的列表。
def changelist_view(self, request, extra_context=None):
try:
action = self.get_actions(request)[request.POST['action']][0]
action_acts_on_all = action.acts_on_all
except (KeyError, AttributeError):
action_acts_on_all = False
if action_acts_on_all:
post = request.POST.copy()
post.setlist(admin.helpers.ACTION_CHECKBOX_NAME,
self.model.objects.values_list('id', flat=True))
request.POST = post
return admin.ModelAdmin.changelist_view(self, request, extra_context)
答案 2 :(得分:5)
def response_action(self, request, queryset):
# override to allow for exporting of ALL records to CSV if no chkbox selected
selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
if request.META['QUERY_STRING']:
qd = dictify_querystring(request.META['QUERY_STRING'])
else:
qd = None
data = request.POST.copy()
if len(selected) == 0 and data['action'] in ('export_to_csv', 'extended_export_to_csv'):
ct = ContentType.objects.get_for_model(queryset.model)
klass = ct.model_class()
if qd:
queryset = klass.objects.filter(**qd)[:65535] # cap at classic Excel maximum minus 1 row for headers
else:
queryset = klass.objects.all()[:65535] # cap at classic Excel maximum minus 1 row for headers
return getattr(self, data['action'])(request, queryset)
else:
return super(ModelAdminCSV, self).response_action(request, queryset)
答案 3 :(得分:2)
有没有办法覆盖它 行为,让行动运行 呢?
我会说不,没有简单的方法。
如果你grep你的错误信息,你会看到代码在django.contrib.admin.options.py
,问题代码在changelist_view的深处。
action_failed = False
selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
# Actions with no confirmation
if (actions and request.method == 'POST' and
'index' in request.POST and '_save' not in request.POST):
if selected:
response = self.response_action(request, queryset=cl.get_query_set())
if response:
return response
else:
action_failed = True
else:
msg = _("Items must be selected in order to perform "
"actions on them. No items have been changed.")
self.message_user(request, msg)
action_failed = True
它也在response_action
函数中使用,所以你不能只是覆盖changelist_template并使用它 - 最简单的方法是定义你自己的动作有效性检查器和跑步者。
如果你真的想使用那个下拉列表,这是一个没有保证的想法。
如何为无选择的管理操作定义新属性:myaction.selectionless = True
在被覆盖的response_action
中复制changelist_view
功能,该功能仅适用于指定了特定标记的操作,然后返回“真实”changelist_view
# There can be multiple action forms on the page (at the top
# and bottom of the change list, for example). Get the action
# whose button was pushed.
try:
action_index = int(request.POST.get('index', 0))
except ValueError:
action_index = 0
# Construct the action form.
data = request.POST.copy()
data.pop(helpers.ACTION_CHECKBOX_NAME, None)
data.pop("index", None)
# Use the action whose button was pushed
try:
data.update({'action': data.getlist('action')[action_index]})
except IndexError:
# If we didn't get an action from the chosen form that's invalid
# POST data, so by deleting action it'll fail the validation check
# below. So no need to do anything here
pass
action_form = self.action_form(data, auto_id=None)
action_form.fields['action'].choices = self.get_action_choices(request)
# If the form's valid we can handle the action.
if action_form.is_valid():
action = action_form.cleaned_data['action']
select_across = action_form.cleaned_data['select_across']
func, name, description = self.get_actions(request)[action]
if func.selectionless:
func(self, request, {})
调用'真实'动作时仍然会出错。如果调用重写的操作,您可以修改request.POST以删除操作。
其他方式涉及黑客攻击太多的东西。我想至少。
答案 4 :(得分:0)
由于对象选择不是您需要的一部分,因此您可以通过创建自己的管理视图来获得最佳服务。
制作自己的管理视图非常简单:
@staff_member_required
装饰器您也可以使用a new 1.1 feature related to this,但您可能会发现我刚才所说的更简单。
答案 5 :(得分:0)
好吧,对于那些顽固到想要这个工作的人来说,这是一个丑陋的黑客(对于django 1.3),即使你没有选择任何东西也会允许任何动作运行。
你必须欺骗原来的changelist_view,以为你选择了一些东西。
class UsersAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
post = request.POST.copy()
if helpers.ACTION_CHECKBOX_NAME not in post:
post.update({helpers.ACTION_CHECKBOX_NAME:None})
request._set_post(post)
return super(ContributionAdmin, self).changelist_view(request, extra_context)
因此,在你的modeladmin中,你覆盖changelist_view,添加到request.POST一个django用来存储所选对象的id的键。
在您的操作中,您可以检查是否没有选定的项目:
if queryset == None:
do_your_stuff()
不言而喻,你不应该这样做。
答案 6 :(得分:0)
我使用以下mixin来创建不需要用户选择至少一个对象的动作。它还允许您获取用户刚刚过滤的查询集:https://gist.github.com/rafen/eff7adae38903eee76600cff40b8b659
这里有一个如何使用它的例子(有关如何在链接上使用它的更多信息):
@admin.register(Contact)
class ContactAdmin(ExtendedActionsMixin, admin.ModelAdmin):
list_display = ('name', 'country', 'state')
actions = ('export',)
extended_actions = ('export',)
def export(self, request, queryset):
if not queryset:
# if not queryset use the queryset filtered by the URL parameters
queryset = self.get_filtered_queryset(request)
# As usual do something with the queryset
答案 7 :(得分:0)
我对@AndyTheEntity响应进行了更改,以避免每行调用一次。
def changelist_view(self, request, extra_context=None):
actions = self.get_actions(request)
if (actions and request.method == 'POST' and 'index' in request.POST and
request.POST['action'].startswith('generate_report')):
data = request.POST.copy()
data['select_across'] = '1'
request.POST = data
response = self.response_action(request, queryset=self.get_queryset(request))
if response:
return response
return super(BaseReportAdmin, self).changelist_view(request, extra_context)
答案 8 :(得分:0)
我找到的最简单的解决方案是按照Django docs创建django admin函数,然后在您的网站admin中随机选择任何对象并运行该函数。这会将该项传递给您的函数,但您根本不会在任何地方使用它,因此它是多余的。为我工作。