[Django]-Django admin default filter

22πŸ‘

A bit more reusable approach:

class DefaultFilterMixIn(admin.ModelAdmin):
    def changelist_view(self, request, *args, **kwargs):
        from django.http import HttpResponseRedirect
        if self.default_filters:
            try:
                test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])
                if test and test[-1] and not test[-1].startswith('?'):
                    url = reverse('admin:%s_%s_changelist' % (self.opts.app_label, self.opts.module_name))
                    filters = []
                    for filter in self.default_filters:
                        key = filter.split('=')[0]
                        if not request.GET.has_key(key):
                            filters.append(filter)
                    if filters:                        
                        return HttpResponseRedirect("%s?%s" % (url, "&".join(filters)))
            except: pass
        return super(DefaultFilterMixIn, self).changelist_view(request, *args, **kwargs)            

And then just define a default_filters on your ModelAdmin:

class YourModelAdmin(DefaultFilterMixIn):
    ....
    default_filters = ('snapshot__exact=0',)
πŸ‘€glic3rinu

8πŸ‘

Finally, this is what I was looking for:

def changelist_view(self, request, extra_context=None):
    if not request.GET.has_key('status__exact'):
        q = request.GET.copy()
        q['status__exact'] = '1'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()
    return super(SoumissionAdmin,self).changelist_view(request, extra_context=extra_context)

The other way, with the queryset method in the admin class does not work. In fact it does filter the results, but it leaves the filter functionality broken.

The solution I’ve found is not perfect either, it’s not possible when using it to select the β€œAll/ filter. In my case it’s not dramatic and it will be good enough though..

πŸ‘€h3.

7πŸ‘

You can override the queryset

class QuoteAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        return super(QuoteAdmin,self).get_queryset(request).filter(status="accepted")

However by overriding the queryset you won’t ever be able to view quotes that do not have status β€œaccepted”.

Alternatively, you can link to the following URL, adding the filter to the GET parameters.

/admin/myapp/quote/?status=accepted
πŸ‘€Alasdair

6πŸ‘

I solved this problem with support β€˜all’.

in models.py:

STATUSES_CHOICE = (
    ('0', 'Active'),
    ('1', 'Deactive'),
    ('2', 'Suspended'),
)

class Client(models.Model):
    ...
    status = models.IntegerField(verbose_name=_('Status'),
                                 default=0,
                                 db_index=True)

in admin.py:

class StatusAdminFilter(SimpleListFilter):
    title = _('Status')
    parameter_name = 'status'
    all_param_value = 'all'

    def lookups(self, request, model_admin):
        return STATUSES_CHOICE

    def queryset(self, request, queryset):
        status = self.value()
        try:
            return (queryset if status == self.all_param_value else
                    queryset.filter(status=int(status)))
        except ValueError:
            raise Http404

    def choices(self, cl):
        yield {'selected': self.value() == self.all_param_value,
               'query_string': cl.get_query_string(
                   {self.parameter_name: self.all_param_value}, 
                   [self.parameter_name]),
               'display': _('All')}
        for lookup, title in self.lookup_choices:
            yield {'selected': self.value() == lookup,
                   'query_string': cl.get_query_string(
                       {self.parameter_name: lookup}, []),
                   'display': title}


class ClientAdmin(admin.ModelAdmin):
    list_filter = (StatusAdminFilter,)

    def changelist_view(self, request, extra_context=None):
        if not request.GET.has_key('status'):
            q = request.GET.copy()
            q['status'] = '0'  # default value for status
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(ClientAdmin, self).changelist_view(
            request, extra_context=extra_context)
πŸ‘€liminspace

5πŸ‘

Short and clean solution. Works nice with β€œAll” option when clicked on change list view.

    def changelist_view(self, request, extra_context=None):
        if not request.META['QUERY_STRING'] and \
            not request.META.get('HTTP_REFERER', '').startswith(request.build_absolute_uri()):
            return HttpResponseRedirect(request.path + "?status__exact=1")
        return super(YourModelAdmin,self).changelist_view(request, extra_context=extra_context)
πŸ‘€Simanas

2πŸ‘

I think I’ve found a way to do this without limiting the user. Just look at the referer to determine if the user just arrived at this page. If so redirect them to the default url you want based on that filter.

def changelist_view(self, request, extra_context=None):
    try:
        test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])
        if test and test[-1] and not test[-1].startswith('?') and not request.GET.has_key('status__exact'):
            return HttpResponseRedirect("/admin/app/model/?status__exact=1")
    except: pass # In case there is no referer
    return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
πŸ‘€Bufke

1πŸ‘

This worked for me and avoided having the β€œAll” problem mentioned by h3.

class MyAdmin(admin.ModelAdmin):
  def changelist_view(self, request, extra_context=None):
    referer = request.META.get('HTTP_REFERER', '')
    showall = request.META['PATH_INFO'] in referer and not request.GET.has_key('timeframe')
    if not showall and not request.GET.has_key('param_name_here'):
        q = request.GET.copy()
        q['param_name_here'] = 'default_value_here'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()
    return super(SerializableAdmin,self).changelist_view(request, extra_context=extra_context)
πŸ‘€Joe Tricarico

1πŸ‘

Here is my update for glic3rinu’s code (see comment there), which works on Python 3.4 and Django 1.9.7:

class DefaultFilterMixIn(admin.ModelAdmin):
    def changelist_view(self, request, *args, **kwargs):
        from django.http import HttpResponseRedirect
        if self.default_filters:
            #try:
                test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])
                if test and test[-1] and not test[-1].startswith('?'):
                    url = reverse('admin:{}_{}_changelist'.format(self.opts.app_label, self.opts.model_name))
                    filters = []
                    for filter in self.default_filters:
                        key = filter.split('=')[0]
                        if not key in request.GET:
                            filters.append(filter)
                    if filters:                     
                        return HttpResponseRedirect("{}?{}".format(url, "&".join(filters)))
            #except: pass
        return super(DefaultFilterMixIn, self).changelist_view(request, *args, **kwargs)            

0πŸ‘

Here is my attempt to have a default filter set in admin (only tested with Django 1.11):

class ZeroCountListFilter(admin.SimpleListFilter):
    title = _('include zero count')
    parameter_name = 'count'

    def choices(self, changelist):
        yield {
            'selected': self.value() is None or self.value() == 0,
            'query_string': changelist.get_query_string({}, [self.parameter_name]),
            'display': _('No'),
        }
        yield {
            'selected': self.value() == '1',
            'query_string': changelist.get_query_string({self.parameter_name: '1'}, []),
            'display': _("Yes"),
        }

    def lookups(self, request, model_admin):
        return (
            ('0', _('No')),
            ('1', _('Yes')),
        )

    def queryset(self, request, queryset):
        if self.value() is None or self.value() == '0':
            return queryset.exclude(count=0)
        else:
            return queryset

The trick is to check self.value() is None to get the default behaviour

πŸ‘€Gabriel Muj

Leave a comment