首页 > 解决方案 > 自定义 DateRangeFilter 未按预期执行

问题描述

我正在尝试自定义django-filter. DateRangeFilter我已经有一个工作过滤器,可以过滤一系列预设选项,例如过去或即将到来的 30 天。

它还具有用于过滤特定年份的工作选项,尽管是硬编码的,例如:

filters = {

    ...

    ),
    "past_years_minus_1": lambda qs, name: qs.filter(
        **{
            "%s__year" % name: now().year - 1,
        }
    ),
    "past_years_minus_2": lambda qs, name: qs.filter(
        **{
            "%s__year" % name: now().year - 2,
        }
    ),

我希望添加的是动态创建一系列单年选择的能力,特定于被过滤的模型/字段的现有实例。因此,如果有A2019 年开始的模型实例,将会有20192020- 但不会更早的选项,但对于模型,如果合适的话B,会有更多选项。2014

我创建了一个__init__覆盖来确定所需的年份并适当地扩展选项和过滤器(在此示例中,针对 2017、2018、2019 和 2020)。

def __init__(self, *args, **kwargs):
    """ Create filter options for every year of the span of years of the corresponding model instances """
    """ Pass in model as class, field as str """
    model = kwargs.pop("model", None)
    field = kwargs.pop("field", None)
    super(OrderDateRangeFilter, self).__init__(*args, **kwargs)

    if model and field:
        earliest_obj = model.objects.earliest()
        earliest_year = getattr(earliest_obj, field).year

        current_year = dt.date.today().year

        range_of_years = [
            earliest_year + i
            for i in range(current_year - earliest_year)
            if earliest_year + i <= current_year
        ]
        range_of_years.reverse()

        for year in range_of_years:

            self.choices.append((f"{year}", _(f"{year}")))

            self.filters[f"{year}"] = lambda qs, name: qs.filter(
                **{
                    "%s__year" % name: year,
                }
            )

添加的选项按预期呈现(检查select小部件):

  <option value="2020">2020</option>
  <option value="2019" selected>2019</option>
  <option value="2018">2018</option>
  <option value="2017">2017</option>

url 查询字符串反映了所需的选择:

...&date_delivery_scheduled=2019&client=...

但是底层过滤器并没有像我预期的那样执行:返回的结果总是只针对第一年(2017 年),无论选择什么年份,​​并且通过django-debug-toolbar显示报告的底层 SQLdjango-filter最终构建一个查询以仅返回第一个年:

SELECT ••• FROM "sales_order" WHERE "sales_order"."date_delivery_scheduled" BETWEEN '2017-01-01'::date AND '2017-12-31'::date

正如我所说,如果我对过滤器进行硬编码(例如,明确地用于“2018”等,或者作为过滤器定义中的一系列偏移量,now()则没有问题。它只是__init__使用相同的语法添加过滤器,即有问题。

任何想法都会受到极大的欢迎

标签: django-filter

解决方案


推荐阅读