Django管理员添加自定义过滤器 [英] Django admin add custom filter

查看:91
本文介绍了Django管理员添加自定义过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用django 1.10,我需要显示数据并根据不同模型中的值创建一个过滤器(该模型具有用于管理模板的引用我模型的外键)
这些是我的2个模型:
这一个用于生成模板:

  class Job(models.Model):
公司= models.ForeignKey(Company)
title = models.CharField(max_length = 100,blank = False)
描述= models.TextField(blank = False,默认='')
store = models.CharField(max_length = 100,blank = True,default ='')
phone_number = models.CharField(max_length = 60,null = True,blank = True)

这是另一个对我的第一个持有外键引用的人:

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

Ins在我的模板上,我已经能够显示(最新)开始和结束时间

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

然后我在list_display内部调用它,效果很好。
但是,我在使用这些条件设置过滤器字段时遇到了麻烦。这是正确的(因为一个在另一个引用了我的工作表的表中)。所以我想知道什么是解决此问题的正确方法?我是否需要为过滤器本身创建另一个函数,但是即使那样,我仍然不确定如何在list_filter中调用它。


这是我的Django管理页面的摘要。 / p>

  class JobAdmin(admin.OSMGeoAdmin,ImportExportModelAdmin):
内联= [
]

readonly_fields =('id', start_date,)

raw_id_fields =( company,)

list_filter =(('JobAdDuration__ad_activated,DateRangeFilter),'招聘','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', 到期,观看,招聘,招聘,已付费,已删除,开始日期,结束日期, ad_consultant)


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

编辑:
在此期间,我尝试使用简单的列表过滤器,但我无法使其正常工作。我想用日历(如默认的DateRangeFilter)放置2个输入字段,以表示开始和结束时间,然后根据这些值返回数据。这是我的原型。

  class StartTimeFilter(SimpleListFilter):
title =('开始日期')
parameter_name ='ad_finished'

def查找(自己,请求,model_admin):
#返回JobAdDuration.objects.values_list( ad_finished)
return(
('startDate','stest1'),
('startDate1','test2')


def queryset(self,request ,queryset):
如果不是self.value():
返回queryset


= JobAdDuration.objects.filter(ad_finished__range =(datetime.now() -timedelta(minutes = 45000),datetime.now()))
allJobs = Job.objects.filter(pk__in = [当前分配的current.job.id])
返回allJobs



解决方案

我会选择自定义 FieldListFilter ,因为它允许将过滤器绑定到



接下来我们实际要做的是实现这种过滤器:




  • 构建lookup_kwargs gte和lte并将它们指定为 expected_pa​​rameters

  • 定义选择以返回空列表,否则返回 NotImplementedError

  • 创建表单以进行字段验证

  • 创建仅输出表单的自定义模板,例如{{spec.form}}

  • 如果表单有效,则将其清除后的数据,过滤掉None并过滤queryset,否则将出错(在下面的代码中,错误被忽略)



过滤器代码:

  class StartTimeFilter(admin .filters.FieldListFilter):
#自定义模板,仅输出表单,例如{{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_pa​​rameters,field_name = field_path)

def expect_parameters(self):
return [self.lookup_kwarg_since,self.lookup_kwarg_upto]

#没有预定义的选择
def options(self,cl):
return []

def queryset(self,request,queryset):
如果self.form.is_valid():
filter_params = {
p:self.expected_pa​​rameters()中p的self.form.cleaned_data.get(p)
如果self.form.cleaned_data。 get(p)不是None
}
返回queryset.filter(** filter_p arams)
else:
返回查询集

表格可以如下所示:

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


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:

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

Here is a snippet of my Django admin page.

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

What is we actually do to implement such filter is next:

  • build lookup_kwargs gte and lte and specify them as expected_parameters
  • define choices to return empty list otherwise NotImplementedError
  • create form to care fields validation
  • create custom template which just outputs form, e.g. {{spec.form}}
  • if form is valid take it's cleaned data, filter out Nones and filter queryset otherwise do something with errors (in code below errors are silenced)

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

这篇关于Django管理员添加自定义过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆