Укажите, в каком порядке применять фильтры в django_filters.Набор фильтров

В течение django_filters.FilterSet:

class SomeFilter(django_filters.FilterSet):
    model = SomeModel
    fields = {
        "is_archived": ("exact",),
    }

    include_ancestors = django_filters.BooleanFilter(method="include_ancestors_filter")

    def include_ancestors_filter(self, queryset, name, value):
        pass

как я могу указать, что поле фильтра include_ancestors должно применяться после всех других полей фильтра (например is_archived)?

Это необходимо в моем случае, потому что включение предков зависит от результирующего набора (т.е. зависит от того, какие дочерние элементы были включены на основе всех других фильтров).

Вероятно, вы можете "взломать" это, переместив include_ancestors вниз по списку значений:

class MoveDownForm:
  move_down_field = 'include_ancestors'
  
  @property
  def cleaned_data(self):
    new = old = super().cleaned_data
    if self.move_down_field in old:
      new = {k: v for k, v in old.items() if k != self.move_down_field}
      new['move_down_field'] = old['move_down_field']
    return new

а затем работайте с:

class SomeFilter(django_filters.FilterSet):
    class Meta:
     model = SomeModel
     form = MoveDownForm
     fields = {
        "is_archived": ("exact",),
     }

    include_ancestors = django_filters.BooleanFilter(method="include_ancestors_filter")

    def include_ancestors_filter(self, queryset, name, value):
        pass

Но я бы протестировал это с помощью двух пользовательских фильтров и проверил порядок печати, если вы поменяете местами параметры строки запроса.

class SomeFilter(django_filters.FilterSet):
    include_ancestors = django_filters.BooleanFilter(required=False) # dont add a method

    class Meta:
        model = SomeModel
        fields = {"is_archived": ["exact"]}

    @property
    def qs(self):
        queryset = super().qs # it wont be filtered here

        if self.form.cleaned_data.get("include_ancestors"):
            queryset = self._apply_ancestor_logic(queryset)

        return queryset

    def _apply_ancestor_logic(self, queryset):
        pass

Я бы сделал что-то вроде этого, где я бы не стал присваивать method имя filter, чтобы Django оставлял ancestor filter при выполнении queryset звоните.

Как только все filters будут использованы, я проверю, нужно ли добавлять логику ancestor к возвращаемому queryset или нет.

Вернуться на верх