I was just testing my intermediate admin page and realized that I hit bug 15742. The following comment seems to suggest that my code is wrong:
The problem here involves how the "queryset" is preserved from the original action handler to the code that handles POST for the intermediate page. In the referenced blog post this is done like so:
if not form: form = self.AddTagForm(initial={'_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
This code is not actually using the queryset parameter passed into the action function but rather the list of selected action checkboxes in the post data, which is only going to be the 100 checkboxes on the individual page. The action code should be using the passed queryset parameter, which does contain the full list of all items, rather than this post data. However Django's doc at the moment shows exactly this technique of using the POST data, and that should be fixed.
So, what is the right way that does not involve request.POST.getlist
? Here is what my apply_regex looks like right now:
# apply_regex.py
from django import forms
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.db import transaction
import re
class RegexForm(forms.Form):
_selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
from_regex = forms.CharField(label='From', required=True)
to_regex = forms.CharField(label='To', required=True)
#flags = forms.CharField(label='Flags')
def apply_regex_global(admin, request, queryset, fieldname):
_selected_action = request.POST.getlist(ACTION_CHECKBOX_NAME)
form = None
if 'apply' in request.POST:
form = RegexForm(request.POST)
if form.is_valid():
with transaction.commit_manually():
try:
for o in queryset:
old_value = getattr(o, fieldname)
new_value = re.sub(form.data['from_regex'],
form.data['to_regex'], old_value)
setattr(o, fieldname, new_value)
o.save()
transaction.commit()
finally:
transaction.rollback()
admin.message_user(request, "Successfully applied a regex.")
return HttpResponseRedirect(request.get_full_path())
if not form:
form = RegexForm(initial={'_selected_action': _selected_action})
return render(request, "apply_regex.html", {
'form': form,
'title': 'Apply regex'}
)
# from apply_regex import apply_regex_global
class ProductAdmin(admin.ModelAdmin):
list_display = ('product', 'vendor', 'devicetype')
search_fields = ['product', ]
formfield_overrides = make_textarea_use_textinput
actions = ['apply_regex']
def apply_regex(self, request, queryset):
return apply_regex_global(self, request, queryset, "product")
admin.site.register(Product, ProductAdmin)
I've solved this before. See this diff. Basically get the id's from the queryset instead of POST data.
queryset.values_list('id', flat=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With