class InputFilter(admin.SimpleListFilter):
template = 'admin/input_filter.html'
def lookups(self, request, model_admin):
# Dummy, required to show the filter.
return ((),)
def choices(self, changelist):
# Grab only the "all" option.
all_choice = next(super().choices(changelist))
all_choice['query_parts'] = (
(k, v)
for k, v in changelist.get_filters_params().items()
if k != self.parameter_name
)
yield all_choice
class HostnameFilter(InputFilter):
parameter_name = 'hostname'
title = 'Hostname'
def queryset(self, request, queryset):
if self.value() is not None:
switch_obj = Switch.objects.get(hostname=self.value().strip())
return queryset.filter(switch=switch_obj)
When I fill in multiple filters it looks like this after enter in vlan-filter (previously the hostname was entered without ‘’):
Before updating Django from 4.2 to 5.2 there was no such problem. What can be done to avoid writing logic for each filter to trim added quotes and square brackets?
The square brackets and quotes suggests that the value is a list, not a string. It’s a list containing one string.
I’m not very familiar with writing custom list filters, so don’t know where you’ve gone wrong, but maybe that will help point you in the right direction (or until someone else comes along).
However, if you fill in only one filter, Django understands the entered values as strings. Wrapping values entered into filters in quotes and brackets is performed when several filters are filled. In Django 4.2 values entered into several filters were treated as strings.
Yes, that’s right. That’s what I wanted to understand, what exactly returns a list, not a string, and at the same time also modifies the original input data in the filter field (in admin view after enter value). This is a Django SimpleListFilter. I was hoping someone could help here.
I want to use the values entered in the field in the filter without transformations. I found out that when entering the first value (By Hostname filter) a
?hostname=Access_FL3_1
is append to the URL. Then, after specifying the value in the second filter (By Vlan filter), the previously appended part of the URL is converted again to:
?hostname=%5B%27Access_FL3_1%27%5D&vlan=1
%5B%27Access_FL3_1%27%5D - this is url encoding for the string:
[‘Access_FL3_1’]
That is, the value of the hostname parameter when specifying values in several filters written as subclasses of SimpleListFilter is a list of one element, as philgyford noted earlier. Because in the URL string:
“[‘Access_FL3_1’]”
and when calling request.GET.get(‘hostname’) or inside the value() method, this is exactly the same string as shown above in the debug.
Does this encoding depend on Django? Perhaps it was different in version 4.2, since there was no such problem with filters. I hope I didn’t tire you out)
By rewriting the value() method for filters, I achieved that after sending the form (filling in the field in the desired filter and entering) the entered data does not change. But according to the encoding in the URL, I see that Django still wraps the entered values in lists. I am sure that there must be a more elegant way to implement filters like mine. After all, the changes in SimpleListFilter from version Django 4.2 were made for the convenience of developers, but in my case everything only became more complicated). Maybe you know what exactly in Django is responsible for forming URLs (encoding) when adding filters? Or what in SimpleListFilter wraps the entered data in a list? It seems that I am not using the SimpleListFilter class correctly to implement my filters in the context of Django 5.2.
I don’t know how to say it another way. The template is expecting the value it outputs to be a string. It is receiving a list containing one element. You need to look at your code and see where the value is a list containing one element, and not a string.
Presumably the v in your list comprehension is a list? Have you checked this yet? What do you see in the console if you print(all_choice['query_parts']) from inside the choices() method?
Side note from the moderator: Please do not continue to post images of code. When you need to post code, copy/paste the code into the body of your post, marked as preformatted text.
(All textual data should be posted as text. This would also include templates, html, and error messages.)
request.GET
<QueryDict: {'hostname': ["['Access_FL3_1']"], 'vlan': ['1']}>
special variables
function variables
encoding:'utf-8'
_assert_mutable:<bound method QueryDict._assert_mutable of <QueryDict: {'hostname': ["['Access_FL3_1']"], 'vlan': ['1']}>>
_encoding:'utf-8'
_getlist:<bound method MultiValueDict._getlist of <QueryDict: {'hostname': ["['Access_FL3_1']"], 'vlan': ['1']}>>
_mutable:False
'hostname':"['Access_FL3_1']"
'vlan':'1'
len():2
request.GET is an immutable Django object, and here you can see that after I entered a value into the second filter (By Vlan), in request.GET it immediately turns into a list. So it’s not my code modifies the values entered into the filters, right?
(Agreeing with Ken; screenshots are hard to read on small devices and impossible for screen readers. And they make it impossible for anyone to copy and paste code/errors into replies so they can help you.)
As you can see, you’re setting the value of the “hostname” to ["['Access_FL3_1']"] which seems wrong doesn’t it?
I don’t know how you came up with this method, but googling it looks the same as the one in this 8 year old gist. If you scroll down that page you’ll see someone added a “Django 5 compatible version” of which a later commenter said, “This fixed the problem with extra square brackets and quotes for me, thanks.”