theme template link custom changelist_view actions python django django-admin

python - template - django admin theme



Filtro personalizado en Django Admin en Django 1.3 o inferior (8)

Aquí está la respuesta e implementado el filtro personalizado tan simple como sea posible esto podría ayudar

Filtro de rango de fechas de administración de Django

¿Cómo puedo agregar un filtro personalizado a django admin (los filtros que aparecen en el lado derecho de un tablero de instrumentos modelo)? Sé que es fácil incluir un filtro basado en un campo de ese modelo, pero ¿qué pasa con un campo "calculado" como este?

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


El usuario suministra productos a algunos países sin franqueo. Yo quería filtrar esos países:

Todos los países, , sin franqueo, sin franqueo pagado.

La respuesta principal para esta pregunta no funcionó para mí (Django 1.3). Creo que no se proporcionó el parámetro field_path en el método __init__ . También se subclasificó DateFieldFilterSpec . El campo de postage es un 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))

En self.links proveemos dicts. usado para construir cadenas de consulta HTTP como ?postage__exact=0 para cada uno de los filtros posibles. Los filtros creo que son acumulativos, por lo tanto, si hubo una solicitud anterior de ''No'' y ahora tenemos una solicitud para ''Sí'', debemos eliminar la consulta ''No''. self.removes especifica qué debe eliminarse para cada consulta. El método de choices construye las cadenas de consulta, dice qué filtro ha sido seleccionado y establece el nombre mostrado del filtro.



Gracias a gpilotino por darme el empujón en la dirección correcta para implementar esto.

Me di cuenta de que el código de la pregunta está usando una fecha y hora para averiguar cuándo es en vivo. Entonces usé DateFieldFilterSpec y lo subclassed.

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

Para usar, puede poner el código anterior en un filters.py e importarlo en el modelo al que desea agregar el filtro


No es una forma óptima (en cuanto a la CPU) pero simple y funcionará, así que lo hago de esta manera (para mi pequeña base de datos). Mi versión de Django es 1.6.

En 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)

La idea clave aquí es acceder a los campos personalizados en un QuerySet a través de la función __call __ () .


No puedes, desafortunadamente. Actualmente, los elementos que no son de campo no se pueden usar como entradas de list_filter.

Tenga en cuenta que su clase de administrador no habría funcionado, incluso si fuera un campo, ya que una tupla de un solo elemento necesita una coma: (''is_live'',)


Solo una nota al margen: puede usar los ticks de sorficación en el administrador de Django más fácilmente de esta manera:

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