Django 1.2中Django管理员页面日期字段的自定义过滤器

3

这个Django 1.2的语法还有效吗?

在Django 1.3或以下版本中使用Django管理工具中的自定义筛选器

我已经尝试过,但是管理类中的list_filter选项没有识别出我的自定义筛选器。应该如何将自定义筛选器添加到list_filter中以便显示?

    class MyModelAdmin(admin.ModelAdmin):
        ...
        list_filter = ['is_expired_filter']

这里,我的“is_expired_filter”是我新注册的自定义过滤器,作者说他是这样做的:

    list_filter = ('is_live')

但是这个在Django中不被识别,当我加载admin页面时得到的错误是:
异常类型: ImproperlyConfigured 异常值: 'PositionAdmin.list_filter[2]' 引用了模型'Position'中缺失的字段 'is_expired_filter'
也许我的错误在于我不确定原始代码在问题作者实现自定义筛选器时如何使用。
以下是原始代码:
    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

你读了你提供的链接中的答案还是只看了问题? - Bryce Siedschlaw
我已经仔细研究了相关的Django API,但似乎还有些东西我没搞清楚。请问能否告诉我我漏掉了什么? - user773328
你的 is_expired_filter 是模型中的一个字段吗? - Bryce Siedschlaw
此外,如果它不是模型字段,那么它应该过滤哪个领域?更多信息会很好。 - Bryce Siedschlaw
唯一的问题是,我认为 is_expired_filter 不是一个字段。我认为他希望它是基于多个字段的自定义过滤器。 - Bryce Siedschlaw
感谢您迄今为止对理解我的问题所做的尝试。也许问题是-我如何将自定义过滤器连接到模型中的字段?自定义过滤器仅基于一个字段,它是' DateFieldFilterSpec '的子类,并根据Django API /之前的答案在filters.py文件中定义。 - user773328
2个回答

2

现在我已经明白了你想要什么,我假设你有一个模型,想要按照DateField进行过滤,例如:

class Position(models.Model):
    expiration_date = models.DateField()
    ...

现在您应该修改为

class Position(models.Model):
    expiration_date = models.DateField()
    expiration_date.is_expired_filter = True
    ...

你需要做的是在admin.py中添加一个新的过滤器类。
from django.contrib.admin.filterspecs import FilterSpec, DateFieldFilterSpec
from django.utils.translation import ugettext as _
from datetime import datetime, date
class ExpiredFilterSpec(DateFieldFilterSpec):
    """
    Adds filtering by future and previous values in the admin
    filter sidebar. Set the is_expired_filter filter in the model field
    attribute 'is_expired_filter'.
    my_model_field.is_expired_filter = True
    """
    def __init__(self, f, request, params, model, model_admin, **kwargs):
        super(ExpiredFilterSpec, self).__init__(f, request, params, model,
                                                model_admin, **kwargs)
        today = date.today()
        self.links = (
            (_('All'), {}),
            (_('Not Expired'), {'%s__lt' % self.field.name: str(today),
                   }),
            (_('Expired'), {'%s__gte' % self.field.name: str(today),
                    }))
    def title(self):
        return "Filter By Expiration Date"
# registering the filter
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_expired_filter', False),
                                   ExpiredFilterSpec))


class PositionAdmin(admin.ModelAdmin):
    list_filter = ['expiration_date']

谢谢你的回答。上周五我尝试时它没有正常工作。新的自定义过滤器出现在管理页面上,但实际上并没有起作用,所以当你点击其中一个选项(在这个例子中选项是“已过期”或“未过期”),对象列表中什么也没有改变。 我明天会在一个全新干净的项目上再试一次。 - user773328
好的,我刚刚按照原样尝试了一下,但是它没有起作用,主要是由于将DateFielddatetime.now()进行比较(它正在给出?e=1标志)。当我之前尝试时,我对其进行了自定义以使其对我有用。因此,请将today = datetime.now()更改为date.today(),然后一切都应该没问题。(确保也存在from datetime import date。) - dr jimbob
非常感谢!它运行得很好。我进行了一项更改,即明确将可选关键字参数设置为None,以避免出现类型错误。我将 (f, request, params, model, model_admin) 更改为 (f, request, params, model, model_admin, field_path=None)。通过这个努力,我学到了很多有关如何阅读和使用 Django 源代码的知识。 - user773328
@user773328:没问题。我没有遇到那个错误,但是我决定在__init__函数的参数末尾添加**kwargs并调用超类的__init__函数是有意义的。 - dr jimbob

0

几乎是把你的链接 Custom Filter in Django Admin on Django 1.3 or below 原封不动地复制过来,我得出了这个结果。



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 IsExpiredFilterSpec(DateFieldFilterSpec):
    """
    Adds filtering by future and previous values in the admin
    filter sidebar. Set the is_expired_filter filter in the model field 
    attribute 'is_expired_filter'.
    my_model_field.is_expired_filter = True
    """

    def __init__(self, f, request, params, model, model_admin):
        super(IsExpiredFilterSpec, self).__init__(f, request, params, model,
                                                   model_admin)
         # -- You'll need to edit this to make it do what you want. --
#        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 Expired"

\# registering the filter
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_expired_filter', False),
                                   IsExpiredFilterSpec))

class MyModelAdmin(admin.ModelAdmin):
    ...
    MODEL_FIELD_TO_FILTER.is_expired_filter = True
    list_filters = ['MODEL_FIELD_TO_FILTER']

更新:感谢jimbob的建议,我进行了更改。MODEL_FIELD_TO_FILTER应该是您想要过滤的字段。


请注意:MyModelAdmin 上面的所有内容都可以放在您的 filters.py 文件中。 - Bryce Siedschlaw
谢谢。我在尝试这个的时候有一个快速问题- 我不应该在filters.py文件中指定DateTime字段的名称吗?如果不是,他们如何知道要与哪个日期时间字段进行比较? - user773328
这就是我无法理解的地方... 似乎传递到__init__中的“f”变量包含字段名称...但是,除非您执行了类似于self.fields ['MYFIELD'] .is_expired_filter = True的操作,否则它将不知道要查找哪个字段。 - Bryce Siedschlaw
这几乎就是了。假设被过滤的DateField被称为expiration_date,您想要在模型定义中添加expiration_date.is_expired_filter = True,然后在ModelAdmin中使用list_filter = ['expiration_date'] - dr jimbob
谢谢,我已经做出了调整。 - Bryce Siedschlaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接