Development Tip

Django 1.3 이하의 Django Admin에서 사용자 지정 필터

yourdevel 2020. 10. 24. 11:56
반응형

Django 1.3 이하의 Django Admin에서 사용자 지정 필터


django admin (모델 대시 보드의 오른쪽에 표시되는 필터)에 사용자 정의 필터를 추가하려면 어떻게해야합니까? 해당 모델의 필드를 기반으로하는 필터를 쉽게 포함 할 수 있다는 것을 알고 있지만 다음과 같은 "계산 된"필드는 어떻습니까?

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

이를 구현하기위한 올바른 방향으로 나에게 밀어주는 gpilotino에게 감사드립니다.

질문의 코드가 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에 넣고 필터를 추가하려는 모델로 가져올 수 있습니다.


사용자 정의 FilterSpec을 작성해야합니다 (어디서나 문서화하지 않음). 여기에서 예를 찾으십시오.

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


현재 django 개발 버전에는 사용자 정의 필터가 지원됩니다 : https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter


불행히도 할 수 없습니다. 현재 필드가 아닌 항목은 list_filter 항목으로 사용할 수 없습니다.

단일 항목 튜플에는 쉼표가 필요하므로 관리자 클래스가 필드 인 경우에도 작동하지 않았을 것입니다. ('is_live',)


참고 사항 : Django 관리자에서 귀머거리 틱을 다음과 같이 더 쉽게 사용할 수 있습니다.

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

최적의 방법 (CPU 측면)은 아니지만 간단하고 작동하므로이 방법을 사용합니다 (소형 데이터베이스의 경우). 내 Django 버전은 1.6입니다.

admin.py에서 :

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 __ () 함수 를 통해 QuerySet의 사용자 정의 필드에 액세스하는 것 입니다.


사용자는 일부 국가에 무료로 상품을 공급합니다. 해당 국가를 필터링하고 싶었습니다.

All - all countries, Yes - postage free, No - charged postage.

The main answer for this question did not work for me (Django 1.3) I think because there was no field_path parameter provided in the __init__ method. Also it subclassed DateFieldFilterSpec. The postage field is a 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))

In self.links we supply dicts. used to construct HTTP query strings like ?postage__exact=0 for each of the possible filters. Filters I think are cumulative so if there was a previous request for 'No' and now we have a request for 'Yes' we have to remove the 'No' query. self.removes specifies what needs to be removed for each query. The choices method constructs the query strings, says which filter has been selected and sets the displayed name of the filter.


Here is the answer and implemented the custom filter as simple as possible this might help

Django admin date range filter

참고URL : https://stackoverflow.com/questions/991926/custom-filter-in-django-admin-on-django-1-3-or-below

반응형