デフォルトのフィルター選択を「すべて」から変更するにはどうすればよいですか? status
、activate
、pending
の3つの値を持つrejected
という名前のフィールドがあります。 Django admin)でlist_filter
を使用すると、フィルターはデフォルトで「すべて」に設定されますが、デフォルトで保留に設定したいです。
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)
これを実現するにはandサイドバーに使用可能な「すべて」リンク(つまり、保留中ではなくすべてを表示するリンク)が必要です。 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が必要です(サイモンに感謝)
上記の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が設定されていないため、デフォルトのパラメーターを使用してリダイレクトします。これは私にとっては問題ありません。管理者フィルターをクリックするとうまくいきます。
[〜#〜] update [〜#〜]:
警告を回避するために、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 )
単にusereturn queryset.filter()
またはif self.value() is None
とSimpleListFilterの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,
}
フィルター値を事前に選択する代わりに、管理者に表示する前に常にデータを事前にフィルターしたい場合は、代わりにModelAdmin.queryset()
メソッドをオーバーライドする必要があります。
DjangoChoicesを使用したGregの答えのわずかな改善、Python> = 2.5およびもちろんDjango> = 1.4。
from Django.utils.translation import ugettext_lazy as _
from Django.contrib.admin import SimpleListFilter
class OrderStatusFilter(SimpleListFilter):
title = _('Status')
parameter_name = 'status__exact'
default_status = OrderStatuses.closed
def lookups(self, request, model_admin):
return (('all', _('All')),) + OrderStatuses.choices
def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup if self.value() else lookup == self.default_status,
'query_string': cl.get_query_string({self.parameter_name: lookup}, []),
'display': title,
}
def queryset(self, request, queryset):
if self.value() in OrderStatuses.values:
return queryset.filter(status=self.value())
Elif self.value() is None:
return queryset.filter(status=self.default_status)
class Admin(admin.ModelAdmin):
list_filter = [OrderStatusFilter]
ニースのソリューションを提供してくれたGregに感謝します!
私はそれが最善の解決策ではないことを知っていますが、管理テンプレートのindex.htmlを次のように25行目と37行目に変更しました。
25:<th scope="row"><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag_flag__exact=1{% endifequal %}">{{ model.name }}</a></th>
37:<td><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag__exact=1{% endifequal %}" class="changelink">{% trans 'Change' %}</a></td>
フィルタリングが正しく機能するように修正する必要がありました。前のソリューションは、ページが読み込まれたときに機能しました。 「アクション」が実行された場合、フィルターはデフォルトではなく「すべて」に戻りました。このソリューションは、管理者変更ページにデフォルトのフィルターをロードしますが、ページで他のアクティビティが発生した場合、フィルターの変更または現在のフィルターも維持します。すべてのケースをテストしたわけではありませんが、実際には、デフォルトのフィルターの設定がページのロード時にのみ発生するように制限している可能性があります。
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)
querystr = request.META['QUERY_STRING']
# Check the QUERY_STRING value, otherwise when
# trying to filter the filter gets reset below
if querystr is None:
if len(qstr) < 2 or qstr[1] == '':
default_filter = True
except:
default_filter = True
if default_filter:
q = request.GET.copy()
q['registered__isnull'] = 'True'
request.GET = q
request.META['QUERY_STRING'] = request.GET.urlencode()
return super(MyAdmin, self).changelist_view(request, extra_context=extra_context)
少し話題から外れていますが、同様の質問を探してここに来ました。日付までにデフォルトのクエリを探していました(つまり、入力がない場合、timestamp
が 'Today'のオブジェクトのみを表示します)。これにより、質問が少し複雑になります。ここに私が思いついたものがあります:
_from Django.contrib.admin.options import IncorrectLookupParameters
from Django.core.exceptions import ValidationError
class TodayDefaultDateFieldListFilter(admin.DateFieldListFilter):
""" If no date is query params are provided, query for Today """
def queryset(self, request, queryset):
try:
if not self.used_parameters:
now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
self.used_parameters = {
('%s__lt' % self.field_path): str(now + datetime.timedelta(days=1)),
('%s__gte' % self.field_path): str(now),
}
# Insure that the dropdown reflects 'Today'
self.date_params = self.used_parameters
return queryset.filter(**self.used_parameters)
except ValidationError, e:
raise IncorrectLookupParameters(e)
class ImagesAdmin(admin.ModelAdmin):
list_filter = (
('timestamp', TodayDefaultDateFieldListFilter),
)
_
これは、デフォルトのDateFieldListFilter
の単純なオーバーライドです。 _self.date_params
_を設定することにより、フィルタードロップダウンが_self.used_parameters
_に一致するオプションに更新されます。このため、_self.used_parameters
_がこれらのドロップダウン選択の1つで使用されるものであることを保証する必要があります(つまり、「Today」または「Last 7」を使用する場合の_date_params
_ Days 'および_self.used_parameters
_を構築してそれらに一致させます)。
これはDjango 1.4.10で動作するように構築されました
これは古いスレッドかもしれませんが、Google検索でより良い答えを見つけることができなかったため、ソリューションを追加すると考えました。
Changelist_viewのModelAdminで応答したこと(そのDeminic Rodgerまたはha22109かどうかはわかりません)
class MyModelAdmin(admin.ModelAdmin):
list_filter = (CustomFilter,)
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)
次に、カスタムSimpleListFilterを作成する必要があります
class CustomFilter(admin.SimpleListFilter):
title = 'Decommissioned'
parameter_name = 'decommissioned' # i chose to change it
def lookups(self, request, model_admin):
return (
('All', 'all'),
('1', 'Decommissioned'),
('0', 'Active (or whatever)'),
)
# had to override so that we could remove the default 'All' option
# that won't work with our default filter in the ModelAdmin class
def choices(self, cl):
yield {
'selected': self.value() is None,
'query_string': cl.get_query_string({}, [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,
}
def queryset(self, request, queryset):
if self.value() == '1':
return queryset.filter(decommissioned=1)
Elif self.value() == '0':
return queryset.filter(decommissioned=0)
return queryset