python - Django 管理员添加自定义过滤器

标签 python django python-2.7 django-admin django-admin-filters

我正在使用 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)

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

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

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

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

然后我只是在 list_display 中调用它,它工作正常。 但是,我无法使用这些条件设置筛选字段。

如果我只是将它添加到我的 list_filter 中,那么我会收到一个错误,即我的模型中没有这样的字段,这是正确的(因为该字段位于另一个引用我的作业表的表中)。所以我想知道解决这个问题的正确方法是什么?我是否需要为过滤器本身创建另一个函数,但即便如此我也不确定我应该如何在 list_filter 中调用它。

这是我的 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

编辑: 与此同时,我尝试用一​​个简单的列表过滤器来解决它,但我无法让它工作。我想放置 2 个带有日历的输入字段(如默认的 DateRangeFilter),表示开始和结束时间,然后根据这些值返回数据。这是我的简单过滤器的“原型(prototype)”功能,它可以工作,但会返回硬编码数据。

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

 

最佳答案

我会使用自定义的 FieldListFilter,因为它允许根据您的要求将过滤器绑定(bind)到不同的模型字段。

接下来我们要如何实现这样的过滤器:

  • 构建 lookup_kwargs gte 和 lte 并将它们指定为 expected_pa​​rameters
  • 定义选择以返回空列表,否则 NotImplementedError
  • 创建表单以关心字段验证
  • 创建只输出表单的自定义模板,例如{{spec.form}}
  • 如果表单有效,则获取已清理的数据,过滤掉 Nones 并过滤查询集,否则执行错误操作(在下面的代码中,错误被静音)

过滤代码:

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

表格可以简单如下:

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

关于python - Django 管理员添加自定义过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48620168/

相关文章:

python - 在一个 FormWizard 中使用两个模型

python - 通过 Web 访问独立的 GUI 应用程序

python - 从属于帖子的网站获取第一张图片

python - 无法在 Ubuntu Linux 中使用 pip 安装 Python 包 : InsecurePlatformWarning, SSLError,tlsv1 警报协议(protocol)版本

python - 导入模块时到底会发生什么?

python - 非交换符号化(或化简)

python - 提取大于指定大小的连续值组

python - 在 vim 中使用 UltiSnips 自定义自动完成

Python 套接字。操作系统错误: [Errno 9] Bad file descriptor

python - 模拟 Celery 任务方法 apply_async