I’m working with the Django Admin panel and need to set a default filter for a model’s changelist view. When the user opens the changelist page for the first time, I want it to automatically filter by a specific value (e.g., status=”A”). However, when a user selects a different filter (e.g., status=”B”), the default filter (status=”A”) should not be applied.
What I Have Tried:
I’ve overridden the changelist_view method in my ModelAdmin class to check if any status filter is present in the request. If not, I add the default filter (status=A). Here’s what my code looks like:
from django.contrib import admin
from django.shortcuts import redirect
from django.urls import reverse
from .models import Person # Replace with your actual model
class PersonAdmin(admin.ModelAdmin):
list_display = ('name', 'status') # Adjust fields to match your model
list_filter = ('status',) # Adjust filters to match your model
def get_queryset(self, request):
# Get the original queryset without any default filtering
qs = super().get_queryset(request)
return qs
def changelist_view(self, request, extra_context=None):
# Check if any filters related to 'status' are already applied by looking at request.GET
if 'status' not in request.GET and 'status__exact' not in request.GET:
# Redirect to the same changelist URL with the default filter applied
query = request.GET.copy() # Make a mutable copy of GET parameters
query['status'] = 'A' # Set the default filter value for 'status' to 'A'
# Redirect to the changelist URL with the correct query string
return redirect(
f"{reverse('admin:Human_Resource_Management_person_changelist')}?{query.urlencode()}"
)
# Call the original changelist_view method
return super().changelist_view(request, extra_context=extra_context)
# Register your admin class with the associated model
admin.site.register(Person, PersonAdmin)
The code works initially: when the changelist view loads without any filters, it defaults to status=A. However, if a user selects another filter, such as status=B, the URL ends up looking like this:
?status=A&status__exact=B
This results in both filters being applied simultaneously, which is incorrect. I want to only have the user-selected filter (e.g., status=B) applied and not keep the default filter (status=A) in the URL.
What I’ve Tried:
I tried modifying request.GET directly, but that caused an AttributeError since request.GET is immutable.
I also tried more complex condition checks, but I can’t seem to prevent the status=A filter from staying in the URL when another filter is selected.
What I’m Looking For:
I’m looking for a solution that:
Applies the default filter (status=A) only when no other status filter is present.
Removes the default filter when the user selects a different filter (status=B) to avoid conflicting filters in the URL.
Any insights or suggestions on how to achieve this would be greatly appreciated!
Thank you!
1
The filter throws out the previous one with the same name. But you use status
, not status__exact
, hence the problem. Use status__exact
instead:
class PersonAdmin(admin.ModelAdmin):
# …
def changelist_view(self, request, extra_context=None):
if 'status' not in request.GET and 'status__exact' not in request.GET:
# Redirect to the same changelist URL with the default filter applied
query = request.GET.copy() # Make a mutable copy of GET parameters
query['status__exact'] = 'A' # Set the default filter value for 'status' to 'A'
# Redirect to the changelist URL with the correct query string
return redirect(
f"{reverse('admin:Human_Resource_Management_person_changelist')}?{query.urlencode()}"
)
# Call the original changelist_view method
return super().changelist_view(request, extra_context=extra_context)
0