theme - Django admin filtro predeterminado
django tutorial (9)
Sé que ya logré hacer esto, pero no recuerdo cómo ni tampoco puedo encontrar ninguna documentación sobre esto ...
¿Cómo se puede aplicar un filtro por defecto en una vista de lista de objetos en el administrador?
Tengo una aplicación que enumera las citas y esas citas tienen un estado (por ejemplo, aceptado, rechazado, en espera ...).
Quiero que el filtro esté configurado en estado = ''aceptado'' por defecto, es decir ...
Aquí está mi actualización para el código de glic3rinu (ver comentario aquí), que funciona en Python 3.4 y 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)
Aquí está mi intento de tener un filtro predeterminado configurado en admin (solo probado con 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
El truco es verificar self.value() is None
para obtener el comportamiento predeterminado
Creo que he encontrado una manera de hacer esto sin limitar al usuario. Solo mire al remitente para determinar si el usuario acaba de llegar a esta página. Si es así, rediríjalos a la URL predeterminada que desea en función de ese filtro.
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)
Esto funcionó para mí y evitó tener el problema "Todo" mencionado por 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)
Finalmente, esto es lo que estaba buscando:
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)
De otro modo, con el método queryset en la clase admin no funciona. De hecho, filtra los resultados, pero deja la funcionalidad del filtro rota.
La solución que encontré tampoco es perfecta, no es posible cuando se usa para seleccionar "Todos / filtro". En mi caso no es dramático y será lo suficientemente bueno ...
Puede anular el queryset
class QuoteAdmin(admin.ModelAdmin):
def get_queryset(self, request):
return super(QuoteAdmin,self).get_queryset(request).filter(status="accepted")
Sin embargo, al anular el conjunto de consultas, nunca podrá ver las cotizaciones que no tengan el estado "aceptado".
Alternativamente, puede vincular a la siguiente URL, agregando el filtro a los parámetros GET.
/admin/myapp/quote/?status=accepted
Resolví este problema con soporte ''todos''.
en modelos.py:
STATUSES_CHOICE = (
(''0'', ''Active''),
(''1'', ''Deactive''),
(''2'', ''Suspended''),
)
class Client(models.Model):
...
status = models.IntegerField(verbose_name=_(''Status''),
default=0,
db_index=True)
en 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)
Solución corta y limpia. Funciona bien con la opción "Todos" cuando se hace clic en la vista de lista de cambios.
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)
Un enfoque un poco más reutilizable:
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)
Y luego simplemente defina los filtros predeterminados en su ModelAdmin:
class YourModelAdmin(DefaultFilterMixIn):
....
default_filters = (''snapshot__exact=0'',)