[英]Django admin add custom filter
i'm using django 1.10 and I need to display data and create a filter based on a value from a different model(which has a foreign key referencing my model that is used on the admin template) These are my 2 models: This one is used to generate the template:我正在使用 django 1.10,我需要显示数据并根据来自不同模型的值创建过滤器(它有一个外键引用我在管理模板上使用的模型)这些是我的 2 个模型:这是用于生成模板:
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)
This is the other one that holds a foreign key reference to my first one:这是另一个持有对我的第一个外键引用的:
class JobAdDuration(models.Model):
job = models.ForeignKey(Job)
ad_activated = models.DateTimeField(auto_now_add=True)
ad_finished = models.DateTimeField(blank=True, null=True)
Inside my template, I have been able to display the(latest)start and end times在我的模板中,我已经能够显示(最新)开始和结束时间
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
And then I just call this inside the list_display and that is working fine.然后我只是在 list_display 中调用它,这工作正常。 However, i have trouble setting a filter field using these criteria.但是,我无法使用这些条件设置过滤器字段。
If I just add it to my list_filter then I get an error that there is no such field inside my model which is true (since that one is in another table that has reference to my job table).如果我只是将它添加到我的 list_filter 中,那么我会收到一个错误,即我的模型中没有这样的字段,这是真的(因为那个字段在另一个表中,该表引用了我的工作表)。 So I was wondering what is the right approach to solve this?所以我想知道解决这个问题的正确方法是什么? Do I need to create another function for the filter itself but even then I'm not sure how should I call it inside the list_filter.我是否需要为过滤器本身创建另一个函数,但即便如此,我也不知道我应该如何在 list_filter 中调用它。
Here is a snippet of my Django admin page.这是我的 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
EDIT: In the meantime, I tried to solve it with a simple list filter, but I am unable to get it to work.编辑:同时,我尝试用一个简单的列表过滤器来解决它,但我无法让它工作。 I would like to place 2 input fields with a calendar(like the default DateRangeFilter) that would represent the start and end time, and then return data based on those values.我想放置 2 个带有日历的输入字段(如默认的 DateRangeFilter),代表开始和结束时间,然后根据这些值返回数据。 This is my "prototype" functionality for the simple filter, it works but it returns hard-coded data.这是我的简单过滤器的“原型”功能,它可以工作,但它返回硬编码数据。
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
I would go with customized FieldListFilter
as it allows to bind filter to different model fields based on your requirements.我会使用自定义的FieldListFilter
因为它允许根据您的要求将过滤器绑定到不同的模型字段。
What is we actually do to implement such filter is next:接下来我们实际做的是实现这样的过滤器:
expected_parameters
构建 lookup_kwargs gte 和 lte 并将它们指定为expected_parameters
NotImplementedError
定义选择返回空列表,否则NotImplementedError
Filter code:过滤代码:
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
Form can be as simple as follows:表格可以简单如下:
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()
This isn't exactly what you've asked for, but you could instead have the filter on the JobAdDuration
modelAdmin.这并不完全是您所要求的,但您可以在JobAdDuration
模型管理员上使用过滤器。 This way, you can get the corresponding jobs filtered according to the ad_activated
and ad_finished
fields.这样,您就可以根据ad_activated
和ad_finished
字段过滤出相应的作业。 And I've added a link to the job
field, so you can directly click it for easier navigation.而且我已经添加了一个指向job
字段的链接,因此您可以直接单击它以更轻松地导航。
To make it a date html5 filter, I've used django-admin-rangefilter library.为了使它成为日期 html5 过滤器,我使用了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'
If you indeed want to go the existing route (filter inside JobAdmin
), then things will get quite complicated.如果您确实想走现有路线(在JobAdmin
过滤),那么事情会变得非常复杂。
I have recently faced similar problem where I needed to filter data based on value from another model.我最近遇到了类似的问题,我需要根据另一个模型的值过滤数据。 This can be done using SimpleListFilter.这可以使用 SimpleListFilter 来完成。 You just need a little tweak in the lookup and queryset function.您只需要在查找和查询集函数中稍作调整。 I will suggest you to install django debug toolbar so that you may know what sql queries are being executed internally by django.我建议你安装 django 调试工具栏,这样你就可以知道 django 内部正在执行哪些 sql 查询。
#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
and in list_filter并在 list_filter 中
list_filter = (StartTimeFilter) # no quotes else it will search for a field in the model 'job'.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.