template related invalid icontains got fields customize python django python-2.7 django-admin django-admin-filters

python - related - inlines django admin



Django admin agrega filtro personalizado (3)

Esto no es exactamente lo que solicitó, pero podría tener el filtro en JobAdDuration modelAdmin. De esta forma, puede obtener los trabajos correspondientes filtrados según los campos ad_activated y ad_finished . Y he agregado un enlace al campo de job , para que pueda hacer clic directamente en él para facilitar la navegación.

Para convertirlo en un filtro html5 de fecha, he usado la biblioteca django-admin-rangefilter .

from django.urls import reverse from django.contrib import admin from .models import Job, JobAdDuration from django.utils.html import format_html from rangefilter.filter import DateRangeFilter @admin.register(JobAdDuration) class JobAdDurationAdmin(admin.ModelAdmin): list_filter = ((''ad_activated'', DateRangeFilter), (''ad_finished'', DateRangeFilter)) list_display = (''id'', ''job_link'', ''ad_activated'', ''ad_finished'') def job_link(self, obj): return format_html(''<a href="{}">{}</a>'', reverse(''admin:job_job_change'', args=[obj.job.id]), obj.job.title) job_link.short_description = ''Job''

Si realmente desea ir a la ruta existente (filtre dentro de JobAdmin ), entonces las cosas se pondrán bastante complicadas.

Estoy usando django 1.10 y necesito mostrar datos y crear un filtro basado en un valor de un modelo diferente (que tiene una clave externa que hace referencia a mi modelo que se usa en la plantilla de administración) Estos son mis 2 modelos: Este es utilizado para generar la plantilla:

class Job(models.Model): company = models.ForeignKey(Company) title = models.CharField(max_length=100, blank=False) description = models.TextField(blank=False, default='''') store = models.CharField(max_length=100, blank=True, default='''') phone_number = models.CharField(max_length=60, null=True, blank=True)

Este es el otro que contiene una referencia de clave externa a mi primera:

class JobAdDuration(models.Model): job = models.ForeignKey(Job) ad_activated = models.DateTimeField(auto_now_add=True) ad_finished = models.DateTimeField(blank=True, null=True)

Dentro de mi plantilla, he podido mostrar las (últimas) horas de inicio y finalización

def start_date(self,obj): if JobAdDuration.objects.filter(job=obj.id).exists(): tempad = JobAdDuration.objects.filter(job=obj).order_by("-id")[0] return tempad.ad_activated

Y luego lo llamo dentro de list_display y está funcionando bien. Sin embargo, tengo problemas para configurar un campo de filtro usando estos criterios.

Si simplemente lo agrego a mi list_filter, obtengo un error que indica que no hay un campo de ese tipo dentro de mi modelo que sea verdadero (ya que está en otra tabla que tiene referencia a mi tabla de trabajo). Entonces me preguntaba ¿cuál es el enfoque correcto para resolver esto? ¿Necesito crear otra función para el filtro en sí mismo, pero aún así no estoy seguro de cómo debería llamarlo dentro del list_filter?

Aquí hay un fragmento de mi página de administración de Django.

class JobAdmin(admin.OSMGeoAdmin, ImportExportModelAdmin): inlines = [ ] readonly_fields = ( ''id'', "start_date", ) raw_id_fields = ("company",) list_filter = ((''JobAdDuration__ad_activated'', DateRangeFilter), ''recruitment'', ''active'', ''deleted'', ''position'', (''created'', DateRangeFilter), ''town'') search_fields = (''title'', ''description'', ''company__name'', ''id'', ''phone_number'', ''town'') list_display = (''title'', ''id'', ''description'', ''active'', ''transaction_number'', ''company'', ''get_position'', ''town'',''created'', ''expires'', ''views'', ''recruitment'', ''recruits'', ''paid'', ''deleted'', "start_date", "end_Date", "ad_consultant") def start_date(self,obj): if JobAdDuration.objects.filter(job=obj.id).exists(): tempad = JobAdDuration.objects.filter(job=obj).order_by("-id")[0] return tempad.ad_activated

EDITAR: Mientras tanto, traté de resolverlo con un filtro de lista simple, pero no puedo hacer que funcione. Me gustaría colocar 2 campos de entrada con un calendario (como el DateRangeFilter predeterminado) que representaría la hora de inicio y finalización, y luego devolver los datos en función de esos valores. Esta es mi funcionalidad de "prototipo" para el filtro simple, funciona pero devuelve datos codificados.

class StartTimeFilter(SimpleListFilter): title = (''Start date'') parameter_name = ''ad_finished'' def lookups(self, request, model_admin): #return JobAdDuration.objects.values_list("ad_finished") return ( (''startDate'', ''stest1''), (''startDate1'', ''test2'') ) def queryset(self, request, queryset): if not self.value(): return queryset assigned = JobAdDuration.objects.filter(ad_finished__range=(datetime.now() - timedelta(minutes=45000), datetime.now())) allJobs = Job.objects.filter(pk__in=[current.job.id for current in assigned]) return allJobs


Me gustaría ir con FieldListFilter personalizado, ya que permite enlazar filtros a diferentes campos de modelo según sus requisitos.

Lo que realmente hacemos para implementar dicho filtro es lo siguiente:

  • construye gte y lte lookup_kwargs y especifícalos como parámetros_esperados
  • definir opciones para devolver la lista vacía de lo contrario NotImplementedError
  • crear formulario para cuidar la validación de campos
  • crear una plantilla personalizada que solo genere un formulario, por ejemplo, {{spec.form}}
  • Si el formulario es válido, tome sus datos limpios, filtre Nones y filtre queryset. De lo contrario, haga algo con los errores (en el código de abajo se silencian los errores)

Código del filtro:

class StartTimeFilter(admin.filters.FieldListFilter): # custom template which just outputs form, e.g. {{spec.form}} template = ''start_time_filter.html'' def __init__(self, *args, **kwargs): field_path = kwargs[''field_path''] self.lookup_kwarg_since = ''%s__gte'' % field_path self.lookup_kwarg_upto = ''%s__lte'' % field_path super(StartTimeFilter, self).__init__(*args, **kwargs) self.form = StartTimeForm(data=self.used_parameters, field_name=field_path) def expected_parameters(self): return [self.lookup_kwarg_since, self.lookup_kwarg_upto] # no predefined choices def choices(self, cl): return [] def queryset(self, request, queryset): if self.form.is_valid(): filter_params = { p: self.form.cleaned_data.get(p) for p in self.expected_parameters() if self.form.cleaned_data.get(p) is not None } return queryset.filter(**filter_params) else: return queryset

La forma puede ser tan simple como sigue:

class StartTimeForm(forms.Form): def __init__(self, *args, **kwargs): self.field_name = kwargs.pop(''field_name'') super(StartTimeForm, self).__init__(*args, **kwargs) self.fields[''%s__gte'' % self.field_name] = forms.DateField() self.fields[''%s__lte'' % self.field_name] = forms.DateField()


Recientemente he enfrentado un problema similar en el que necesitaba filtrar datos según el valor de otro modelo. Esto se puede hacer usando SimpleListFilter. Solo necesitas un pequeño ajuste en la función de búsqueda y consultas. Le sugeriré que instale la barra de herramientas de depuración de django para que pueda saber qué consultas de SQL se ejecutan internamente por django.

#import your corresponding models first class StartTimeFilter(SimpleListFilter): title = (''Start date'') parameter_name = ''ad_finished'' def lookups(self, request, model_admin): data = [] qs = JobAdDuration.objects.filter() # Note : if you do not have distinct values of ad_activated apply distinct filter here to only get distinct values print qs for c in qs: data.append([c.ad_activated, c.ad_activated]) # The first c.activated is the queryset condition your filter will execute on your Job model to filter data ... and second c.ad_activated is the data that will be displayed in dropdown in StartTimeFilter return data def queryset(self, request, queryset): if self.value(): assigned = JobAdDuration.objects.filter(ad_activated__exact = self.value()) # add your custom filter function based on your requirement return Job.objects.filter(pk__in=[current.job.id for current in assigned]) else: return queryset

y en list_filter

list_filter = (StartTimeFilter) # no quotes else it will search for a field in the model ''job''.