I'm trying to pass in a custom argument to the Django Admin change list view so I can filter the list in a specialized way. I'd like to filter the queryset on 2 fields, start_date and end_date, based on the GET parameter called 'active_pp'. I've gotten the filtering to work correctly, but I'm not able to pass in a GET query parameter that specifies whether I should display the filtered results or the normal results.
I know that, due to security, the Django Admin filters out any query parameters passed to it that aren't related to specified model fields; upon finding bad arguments, the admin redirects the user to the current view but replaces the GET query parameters with e=1. I'd like to whitelist my custom 'active_pp' parameter so the page won't be redirected and I'll be able to use the parameter.
Here is an example of the ModelAdmin in admin.py with the queryset customization.
class FeaduredAdmin(admin.ModelAdmin): .... def get_changelist(self, request, **kwargs): from django.contrib.admin.views.main import ChangeList # Try to get the 'active_pp' query parameter active_pp = request.GET.get('active_pp',None) # Define a custom ChangeList class with a custom queryset class ActiveChangeList(ChangeList): def get_query_set(self, *args, **kwargs): now = datetime.datetime.now() qs = super(ActiveChangeList, self).get_query_set(*args, **kwargs) return qs.filter((Q(start_date=None) | Q(start_date__lte=now)) & (Q(end_date=None) | Q(end_date__gte=now))) # use the custom ChangeList class if the parameter exists if active_pp: return ActiveChangeList return ChangeList
Does anyone know how to whitelist custom GET querystring arguments passed to the change_list?
Thanks for reading and for your consideration, Joe
UPDATE:
Using Uvasal's provided links, I was able to properly whitelist the GET parameter.
class ActiveFilterAminForm(forms.Form): active_pp = forms.CharField() class FeaduredAdmin(admin.ModelAdmin): .... # Based on: http://djangosnippets.org/snippets/2322/ advanced_search_form = ActiveFilterAminForm() def get_changelist(self, request, **kwargs): from django.contrib.admin.views.main import ChangeList active_pp = self.other_search_fields.get('active_pp',None) # now we have the active_pp parameter that was passed in and can use it. class ActiveChangeList(ChangeList): def get_query_set(self, *args, **kwargs): now = datetime.datetime.now() qs = super(ActiveChangeList, self).get_query_set(*args, **kwargs) return qs.filter((Q(start_date=None) | Q(start_date__lte=now)) & (Q(end_date=None) | Q(end_date__gte=now))) if not active_pp is None: return ActiveChangeList return ChangeList def lookup_allowed(self, lookup): if lookup in self.advanced_search_form.fields.keys(): return True return super(MyModelAdmin, self).lookup_allowed(lookup) def changelist_view(self, request, extra_context=None, **kwargs): self.other_search_fields = {} asf = self.advanced_search_form extra_context = {'asf':asf} request.GET._mutable=True for key in asf.fields.keys(): try: temp = request.GET.pop(key) except KeyError: pass else: if temp!=['']: self.other_search_fields[key] = temp request.GET_mutable=False return super(FeaduredProductAdmin, self)\ .changelist_view(request, extra_context=extra_context)
I think you just need to put your custom filter fields in the search_fields class variable as outlined in the Advanced Search Django Snippet.
You should be able to modify the snippet to support date ranges as well.
In summary, here is the undocumented hack used above:
set request.GET._mutable = True
, then request.GET.pop()
off the custom GET argument(s) you are using.
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