Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin Custom Change List Arguments: Override /?e=1

Tags:

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) 
like image 271
Joe J Avatar asked Dec 13 '11 18:12

Joe J


2 Answers

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.

like image 83
dan-klasson Avatar answered Oct 04 '22 15:10

dan-klasson


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.

like image 36
Collin Anderson Avatar answered Oct 04 '22 15:10

Collin Anderson