Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to set _selected_action of Django admin's intermediate page that does not involve request.POST.getlist?

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)
like image 518
d33tah Avatar asked Oct 20 '25 13:10

d33tah


1 Answers

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)

like image 153
Bufke Avatar answered Oct 22 '25 02:10

Bufke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!