[python] Django 관리자의 기본 필터

‘전체’에서 기본 필터 선택을 어떻게 변경할 수 있습니까? , 및 이라는 status세 가지 값 이있는라는 필드 가 있습니다. Django 관리자에서 사용할 때 필터는 기본적으로 ‘모두’로 설정되지만 기본적으로 보류로 설정하고 싶습니다.activatependingrejectedlist_filter



답변

이를 달성 하고 사이드 바에 사용 가능한 ‘모두’링크 (즉, 보류 중을 표시하지 않고 모두 표시하는 링크)를 가지려면 django.contrib.admin.filters.SimpleListFilter기본적으로 ‘보류 중’을 상속 하고 필터링 하는 사용자 지정 목록 필터를 만들어야합니다 . 다음 라인을 따라 작동해야합니다.

from datetime import date

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class StatusFilter(SimpleListFilter):
    title = _('Status')

    parameter_name = 'status'

    def lookups(self, request, model_admin):
        return (
            (None, _('Pending')),
            ('activate', _('Activate')),
            ('rejected', _('Rejected')),
            ('all', _('All')),
        )

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

    def queryset(self, request, queryset):
        if self.value() in ('activate', 'rejected'):
            return queryset.filter(status=self.value())    
        elif self.value() == None:
            return queryset.filter(status='pending')


class Admin(admin.ModelAdmin): 
    list_filter = [StatusFilter] 

편집 : Django 1.4 필요 (Simon에게 감사)


답변

class MyModelAdmin(admin.ModelAdmin):   

    def changelist_view(self, request, extra_context=None):

        if not request.GET.has_key('decommissioned__exact'):

            q = request.GET.copy()
            q['decommissioned__exact'] = 'N'
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)


답변

와 비교하여 “모든”의 선택을 할 수 있도록 수정 위의 ha22109의 답변을 툭 HTTP_REFERER하고 PATH_INFO.

class MyModelAdmin(admin.ModelAdmin):

    def changelist_view(self, request, extra_context=None):

        test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])

        if test[-1] and not test[-1].startswith('?'):
            if not request.GET.has_key('decommissioned__exact'):

                q = request.GET.copy()
                q['decommissioned__exact'] = 'N'
                request.GET = q
                request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)


답변

나는이 질문이 지금 꽤 오래되었지만 여전히 유효하다는 것을 알고 있습니다. 이것이 가장 올바른 방법이라고 생각합니다. 본질적으로 Greg의 방법과 동일하지만 쉽게 재사용 할 수 있도록 확장 가능한 클래스로 공식화되었습니다.

from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _

class DefaultListFilter(SimpleListFilter):
    all_value = '_all'

    def default_value(self):
        raise NotImplementedError()

    def queryset(self, request, queryset):
        if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
            return queryset

        if self.parameter_name in request.GET:
            return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})

        return queryset.filter(**{self.parameter_name:self.default_value()})

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

class StatusFilter(DefaultListFilter):
    title = _('Status ')
    parameter_name = 'status__exact'

    def lookups(self, request, model_admin):
        return ((0,'activate'), (1,'pending'), (2,'rejected'))

    def default_value(self):
        return 1

class MyModelAdmin(admin.ModelAdmin):
    list_filter = (StatusFilter,)


답변

리디렉션을 사용하는 일반적인 솔루션은 다음과 같습니다. GET 매개 변수가 있는지 확인하고, 존재하지 않으면 기본 get 매개 변수로 리디렉션합니다. 또한 list_filter 세트가 있으므로이를 선택하고 기본값을 표시합니다.

from django.shortcuts import redirect

class MyModelAdmin(admin.ModelAdmin):

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        referrer = request.META.get('HTTP_REFERER', '')
        get_param = "status__exact=5"
        if len(request.GET) == 0 and '?' not in referrer:
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

유일한주의 사항은 “?”가있는 페이지로 직접 이동할 때입니다. URL에 HTTP_REFERER가 설정되어 있지 않으므로 기본 매개 변수와 리디렉션을 사용합니다. 이것은 나에게 좋습니다. 관리자 필터를 클릭하면 훌륭하게 작동합니다.

업데이트 :

주의 사항을 피하기 위해 changelist_view 기능을 단순화하는 사용자 지정 필터 함수를 작성했습니다. 필터는 다음과 같습니다.

class MyModelStatusFilter(admin.SimpleListFilter):
    title = _('Status')
    parameter_name = 'status'

    def lookups(self, request, model_admin):  # Available Values / Status Codes etc..
        return (
            (8, _('All')),
            (0, _('Incomplete')),
            (5, _('Pending')),
            (6, _('Selected')),
            (7, _('Accepted')),
        )

    def choices(self, cl):  # Overwrite this method to prevent the default "All"
        from django.utils.encoding import force_text
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == force_text(lookup),
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):  # Run the queryset based on your lookup values
        if self.value() is None:
            return queryset.filter(status=5)
        elif int(self.value()) == 0:
            return queryset.filter(status__lte=4)
        elif int(self.value()) == 8:
            return queryset.all()
        elif int(self.value()) >= 5:
            return queryset.filter(status=self.value())
        return queryset.filter(status=5)

이제 changelist_view는 아무것도없는 경우에만 기본 매개 변수를 전달합니다. 아이디어는 get 매개 변수를 사용하지 않고 모두보기 위해 제네릭 필터 기능을 제거하는 것이 었습니다. 모든 것을 보려면 해당 목적을 위해 상태 = 8을 할당했습니다. :

class MyModelAdmin(admin.ModelAdmin):

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        if len(request.GET) == 0:
            get_param = "status=5"
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin, self).changelist_view(request, extra_context=extra_context)


답변

def changelist_view( self, request, extra_context = None ):
    default_filter = False
    try:
        ref = request.META['HTTP_REFERER']
        pinfo = request.META['PATH_INFO']
        qstr = ref.split( pinfo )

        if len( qstr ) < 2:
            default_filter = True
    except:
        default_filter = True

    if default_filter:
        q = request.GET.copy()
        q['registered__exact'] = '1'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super( InterestAdmin, self ).changelist_view( request, extra_context = extra_context )


답변

SimpleListFilter의 return queryset.filter()or if self.value() is None및 Override 메서드를 간단히 사용할 수 있습니다.

from django.utils.encoding import force_text

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