From 9898ccbab782b0dfbb3efe938f8403f937474fb6 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Sat, 29 Oct 2016 12:30:15 -0400 Subject: [PATCH] Add guide/ref docs for request-based filtering --- docs/ref/filters.txt | 17 +++++++++++++++ docs/usage.txt | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/docs/ref/filters.txt b/docs/ref/filters.txt index f3f615294..650e95dc2 100644 --- a/docs/ref/filters.txt +++ b/docs/ref/filters.txt @@ -323,6 +323,22 @@ Example:: model = Book fields = ['author'] +The ``queryset`` argument also supports callable behavior. If a callable is +passed, it will be invoked with ``Filterset.request`` as its only argument. +This allows you to easily filter by properties on the request object without +having to override the ``FilterSet.__init__``. + +.. code-block:: python + + def departments(request): + company = request.user.company + return company.department_set.all() + + class EmployeeFilter(filters.FilterSet): + department = filters.ModelChoiceFilter(queryset=departments) + ... + + ``ModelMultipleChoiceFilter`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,6 +348,7 @@ for ``ManyToManyField`` by default. As with ``ModelChoiceFilter``, if automatically instantiated, ``ModelMultipleChoiceFilter`` will use the default ``QuerySet`` for the related field. If manually instantiated you **must** provide the ``queryset`` kwarg. +Like ``ModelChoiceFilter``, the ``queryset`` argument has callable behavior. To use a custom field name for the lookup, you can use ``to_field_name``:: diff --git a/docs/usage.txt b/docs/usage.txt index 3b5d8a373..ecfc92efc 100644 --- a/docs/usage.txt +++ b/docs/usage.txt @@ -236,11 +236,63 @@ default filters for all the models fields of the same kind using } +Request-based filtering +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``FilterSet`` may be initialized with an optional ``request`` argument. If +a request object is passed, then you may access the request during filtering. +This allows you to filter by properties on the request, such as the currently +logged-in user or the ``Accepts-Languages`` header. + + +Filtering the primary ``.qs`` +""""""""""""""""""""""""""""" + +To filter the primary queryset by the ``request`` object, simply override the +``FilterSet.qs`` property. For example, you could filter blog articles to only +those that are published and those that are owned by the logged-in user +(presumably the author's draft articles). + +.. code-block:: python + + class ArticleFilter(django_filters.FilterSet): + + class Meta: + model = Article + fields = [...] + + @property + def qs(self): + parent = super(ArticleFilter, self).qs + return parent.filter(is_published=True) \ + | parent.filter(author=request.user) + + +Filtering the related queryset for ``ModelChoiceFilter`` +""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The ``queryset`` argument for ``ModelChoiceFilter`` and ``ModelMultipleChoiceFilter`` +supports callable behavior. If a callable is passed, it will be invoked with the +``request`` as its only argument. This allows you to perform the same kinds of +request-based filtering without resorting to overriding ``FilterSet.__init__``. + +.. code-block:: python + + def departments(request): + company = request.user.company + return company.department_set.all() + + class EmployeeFilter(filters.FilterSet): + department = filters.ModelChoiceFilter(queryset=departments) + ... + + Customize filtering with ``Filter.method`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can control the behavior of a filter by specifying a ``method`` to perform filtering. View more information in the :ref:`method reference `. +Note that you may access the filterset's properties, such as the ``request``. .. code-block:: python