2009-06-14 2 views
72

django admin (모델 대시 보드의 오른쪽에 나타나는 필터)에 사용자 정의 필터를 추가하려면 어떻게합니까? 나는 쉬운이 같은 "계산"필드에 대해 해당 모델의 필드를 기준으로 필터,하지만를 포함 알고Django의 사용자 정의 필터 Django 1.3 이하

class NewsItem(models.Model): 
    headline = models.CharField(max_length=4096, blank=False) 
    byline_1 = models.CharField(max_length=4096, blank=True) 
    dateline = models.DateTimeField(help_text=_("date/time that appears on article")) 
    body_copy = models.TextField(blank=False) 

    when_to_publish = models.DateTimeField(verbose_name="When to publish", blank=True, null=True) 

    # HOW CAN I HAVE "is_live" as part of the admin filter? It's a calculated state!! 
    def is_live(self): 
     if self.when_to_publish is not None: 
      if (self.when_to_publish < datetime.now()): 
       return """ <img alt="True" src="/media/img/admin/icon-yes.gif"/> """ 
     else: 
      return """ <img alt="False" src="/media/img/admin/icon-no.gif"/> """  

    is_live.allow_tags = True 

class NewsItemAdmin(admin.ModelAdmin): 
    form = NewsItemAdminForm 
    list_display = ('headline', 'id', 'is_live') 
    list_filter = ('is_live') # how can i make this work?? 
+0

다른 사람들을 돕는이 기능은 트렁크 (1.4 DEV)에 말했다 수있는 대답은 가능한 한 간단하게 사용자 정의 필터를 구현했습니다. 추가 정보 : [릴리스 노트] (https://code.djangoproject.com/browser/django/trunk/docs/releases/1.4.txt?rev=16144#L40) 및 [documentation] (https : // code. djangoproject.com/browser/django/trunk/docs/ref/contrib/admin/index.txt#L604). – Paolo

+1

다음은 문서에 대한 더 나은 링크입니다. SimpleListFilter를 확장하면 여기에 갈 수 있습니다. FilterSpecs가 오래되었습니다. https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter – fastmultiplication

+0

[matley 응답] (https://stackoverflow.com/a/6355234/)을 참조하십시오. 아래 공식 문서에 대한 링크가 있습니다. –

답변

57

감사합니다.

질문의 코드가 datetime을 사용하여 그 라이브가 언제인지 알아 냈습니다. 그래서 DateFieldFilterSpec을 사용하고 하위 클래스를 만들었습니다.

from django.db import models 
from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec,DateFieldFilterSpec 
from django.utils.encoding import smart_unicode 
from django.utils.translation import ugettext as _ 
from datetime import datetime 

class IsLiveFilterSpec(DateFieldFilterSpec): 
    """ 
    Adds filtering by future and previous values in the admin 
    filter sidebar. Set the is_live_filter filter in the model field attribute 
    'is_live_filter'. my_model_field.is_live_filter = True 
    """ 

    def __init__(self, f, request, params, model, model_admin): 
     super(IsLiveFilterSpec, self).__init__(f, request, params, model, 
               model_admin) 
     today = datetime.now() 
     self.links = (
      (_('Any'), {}), 
      (_('Yes'), {'%s__lte' % self.field.name: str(today), 
         }), 
      (_('No'), {'%s__gte' % self.field.name: str(today), 
        }), 

     ) 


    def title(self): 
     return "Is Live" 

# registering the filter 
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_live_filter', False), 
           IsLiveFilterSpec)) 

당신이 filters.py에 위의 코드를 넣을 수 있습니다 사용 및 사용자 정의 필터에 대한 지원이 당신이 현재의 장고 개발 버전에서

+2

이 코드를 사용하여 수행 한 작업의 마지막 부분에 대해 더 자세히 설명 할 수 있습니까? –

+0

Rosarch, 코드의 마지막 줄은 django에 is_live_filter를 등록한 다음 모델 클래스의 article.py에서 article이라고 말하면 publish_date라는 필드가 있습니다. publish_date.is_live_filter –

+1

마지막 줄 * filter_specs.insert *는 다음과 같습니다. 매우 중요합니다. 그렇지 않으면 맞춤 필터가 나타나지 않을 것입니다. 대신 해당 필드 유형에 기본 제공되는 filterspec 중 하나가 표시됩니다. (처음에는 대답을 제대로 읽지 못했고 내장 된 filterspecs와 같은 .register 메서드를 사용했습니다!) – Anentropic

3

당신은 할 수 없습니다, 불행히도. 현재 비 필드 항목은 list_filter 항목으로 사용할 수 없습니다. ('is_live',)

+4

언젠가 mabye, 오픈 티켓입니다. http://code.djangoproject.com/ticket/5833 – imjoevasquez

+2

FWIW, # 5833에 대한 수정이 django 1.4의 django 트렁크에 있습니다. –

22

당신이 FilterSpec은 (어디 documentend되지 않음) 사용자 정의를 작성해야합니다 : 그것은 필드가 있다면 당신의 관리자 클래스는 단일 아이템 튜플로도 일을하지 않았을

참고 쉼표가 필요합니다. 예를 들어 여기를 봐 :이 구현을위한 올바른 방향으로 나에게 밀어주는 gpilotino하는

http://www.djangosnippets.org/snippets/1051/

+1

관련 스 니펫 : http://djangosnippets.org/snippets/1963/ – Eddified

9
+1

을 참조하십시오. 좀 더 구체적으로 설명하려면 다음을 수행하십시오. https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django .contrib.admin.ModelAdmin.list_filter – Webthusiast

+1

@Webthusiast 답변을 수정하여 언제든지 개선 할 수 있습니다. 이 경우 이미 구체적인 URL을 대답에 포함 시켰습니다. –

2

사용자는 우편물을 무료로 일부 국가에 공급합니다. , 우편 요금 무료 아니- -, 모든 국가 - 충전 우표를

모든 : 나는 그 나라를 필터링하고 싶었다.

__init__ 메서드에 제공된 field_path 매개 변수가 없기 때문에이 질문에 대한 주된 대답이 저에게 효과적이지 않았다고 생각합니다 (장고 1.3). 또한 서브 클래스는 DateFieldFilterSpec입니다. postage 필드는 우리가 dicts을 공급 self.links에서는 FloatField

from django.contrib.admin.filterspecs import FilterSpec 

class IsFreePostage(FilterSpec): 

    def __init__(self, f, request, params, model, model_admin, field_path=None): 
     super(IsFreePostage, self).__init__(f, request, params, model, 
      model_admin, field_path) 

     self.removes = { 
      'Yes': ['postage__gt'], 
      'No': ['postage__exact'], 
      'All': ['postage__exact', 'postage__gt'] } 

     self.links = (
      ('All', {}), 
      ('Yes', {'postage__exact': 0}), 
      ('No', {'postage__gt': 0})) 

     if request.GET.has_key('postage__exact'): 
      self.ttl = 'Yes' 
     elif request.GET.has_key('postage__gt'): 
      self.ttl = 'No' 
     else: 
      self.ttl = 'All' 

    def choices(self, cl): 
     for title, param_dict in self.links: 
      yield {'selected': title == self.ttl, 
        'query_string': cl.get_query_string(param_dict, 
         self.removes[title]), 
        'display': title} 
    def title(self): 
     return 'Free Postage' 

FilterSpec.filter_specs.insert(0, 
    (lambda f: getattr(f, 'free_postage', False), IsFreePostage)) 

입니다. 가능한 필터 각각에 대해 ?postage__exact=0과 같은 HTTP 쿼리 문자열을 구성하는 데 사용됩니다. 필터 나는이 누적되어 'No'에 대한 이전 요청이 있었고 지금은 'Yes'에 대한 요청이 있으니 'No'쿼리를 제거해야합니다. self.removes은 각 쿼리에 대해 제거해야 할 것을 지정합니다. choices 메서드는 쿼리 문자열을 구성하고 어떤 필터가 선택되었는지 표시하고 필터의 표시된 이름을 설정합니다.

3

그냥 (!) 참고 : 당신은 deafult를 사용할 수는 다음과 같이 더 쉽게 장고 관리자에 틱 :

def is_live(self): 
    if self.when_to_publish is not None: 
     if (self.when_to_publish < datetime.now()): 
      return True 
    else: 
     return False 

is_live.boolean = True 
3

하지 최적의 방법 (CPU 현명한) 그러나 간단하고 작동합니다, 그래서 나는 이런 식으로 할 (내 작은 데이터베이스 용). 내 Django 버전은 1.6입니다.

관리자평가 :

class IsLiveFilter(admin.SimpleListFilter): 
    title = 'Live' 
    parameter_name = 'islive' 
    def lookups(self, request, model_admin): 
     return (
      ('1', 'islive'), 
     ) 
    def queryset(self, request, queryset): 
     if self.value(): 
      array = [] 
      for element in queryset: 
       if element.is_live.__call__() == True: 
        q_array.append(element.id) 
      return queryset.filter(pk__in=q_array) 

... 여기

class NewsItemAdmin(admin.ModelAdmin): 
    form = NewsItemAdminForm 
    list_display = ('headline', 'id', 'is_live') 
    list_filter = (IsLiveFilter) 

주요 아이디어는 __call __() 기능을 통해 검색어 세트에 사용자 정의 필드를 액세스하는 것입니다.

+0

아마도 가장 최적화 된 방법은 아니지만 간단하고 올바르게 작동하는 방법 일 수 있습니다. 그것은 나를 두통으로 구했다. – d6bels