Django 管理默认过滤器

发布于 2024-09-06 07:44:00 字数 178 浏览 5 评论 0原文

我知道我已经设法做到了这一点,但不记得如何做到这一点,也找不到任何有关此的文档。.

如何在管理中的对象列表视图上默认应用过滤器?

我有一个列出报价的应用程序,这些报价有一个状态(例如:接受、拒绝、保留......)。

我希望默认情况下将过滤器设置为 status='accepted' ,即..

I know I already managed to do this but can't remember how nor I can't find any documentation about this..

How can apply a filter by default on a object list view in the admin ?

I have an app which list quotes and those quotes have a status (ex: accepted, rejected, on hold ..).

I want the filter set on status='accepted' by default that is..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

非要怀念 2024-09-13 07:44:00

更可重用的方法:

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)            

然后只需在 ModelAdmin 上定义一个 default_filters :

class YourModelAdmin(DefaultFilterMixIn):
    ....
    default_filters = ('snapshot__exact=0',)

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',)
诗笺 2024-09-13 07:44:00

最后,这就是我正在寻找的:

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 方法不起作用。事实上,它确实过滤了结果,但它使过滤功能被破坏。

我找到的解决方案也不完美,当使用它来选择“全部/过滤器”时,这是不可能的。就我而言,它并不引人注目,但已经足够好了..

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..

黑寡妇 2024-09-13 07:44:00

您可以覆盖查询集

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

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
等数载,海棠开 2024-09-13 07:44:00

简短而干净的解决方案。单击更改列表视图时,与“全部”选项配合良好。

    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)

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)
多孤肩上扛 2024-09-13 07:44:00

我通过支持“全部”解决了这个问题。

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

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)
提笔书几行 2024-09-13 07:44:00

我想我已经找到了一种在不限制用户的情况下做到这一点的方法。只需查看引荐来源网址即可确定用户是否刚刚到达此页面。如果是这样,根据该过滤器将它们重定向到您想要的默认 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)

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)
好倦 2024-09-13 07:44:00

这对我有用,避免了 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)

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)
失眠症患者 2024-09-13 07:44:00

这是我对 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)            

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)            
醉生梦死 2024-09-13 07:44:00

这是我在 admin 中设置默认过滤器的尝试(仅使用 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 以获得默认行为

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文