Фильтр по умолчанию для администратора Django - PullRequest
21 голосов
/ 18 июня 2010

Я знаю, что уже успел это сделать, но не могу вспомнить, как и не могу найти какую-либо документацию об этом ..

Как применить фильтр по умолчанию к представлению списка объектов в админке?

У меня есть приложение, в котором перечислены цитаты, и эти цитаты имеют статус (например: принято, отклонено, удерживается ..).

Я хочу, чтобы фильтр был установлен по умолчанию в статус = принят, то есть ..

Ответы [ 9 ]

20 голосов
/ 15 марта 2012

Немного более многократно используемый подход:

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)            

А затем просто определите default_filters на вашем ModelAdmin:

class YourModelAdmin(DefaultFilterMixIn):
    ....
    default_filters = ('snapshot__exact=0',)
7 голосов
/ 18 июня 2010

Наконец, это то, что я искал:

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)

Другой способ, с помощью метода queryset в классе admin, не работает.На самом деле он фильтрует результаты, но оставляет функциональность фильтра нарушенной.

Решение, которое я нашел, тоже не идеальное, невозможно использовать его для выбора «Все / фильтр». В моем случаеэто не драматично, и это будет достаточно хорошо, хотя ..

6 голосов
/ 18 июня 2010

Вы можете переопределить набор запросов

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

Однако, переопределив набор запросов, вы никогда не сможете просматривать кавычки, которые не имеют статуса «принято».

Кроме того, вы можете создать ссылку на следующий URL, добавив фильтр к параметрам GET.

/admin/myapp/quote/?status=accepted
5 голосов
/ 08 апреля 2014

Короткое и чистое решение.Хорошо работает с опцией «Все» при нажатии на вид списка изменений.

    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)
5 голосов
/ 14 сентября 2012

Я решил эту проблему с поддержкой 'all'.

в 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)

в 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)
2 голосов
/ 23 мая 2011

Я думаю, что нашел способ сделать это, не ограничивая пользователя. Просто посмотрите на реферера, чтобы определить, пришел ли пользователь на эту страницу. Если это так, перенаправьте их на URL-адрес по умолчанию, который вы хотите, основываясь на этом фильтре.

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)
1 голос
/ 01 июля 2016

Вот мое обновление для кода glic3rinu (см. Комментарий там), которое работает на Python 3.4 и 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)            
1 голос
/ 04 июня 2012

Это сработало для меня и позволило избежать проблемы "Все", упомянутой 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)
0 голосов
/ 18 августа 2017

Вот моя попытка установить фильтр по умолчанию в админке (протестировано только с 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

Хитрость в том, чтобы проверить self.value() is None, чтобы получить поведение по умолчанию

...