Separate tips from usage guide
This commit is contained in:
parent
4b459cfdab
commit
046b31b391
|
@ -0,0 +1,90 @@
|
|||
==================
|
||||
Tips and Solutions
|
||||
==================
|
||||
|
||||
Common problems for declared filters
|
||||
------------------------------------
|
||||
|
||||
Below are some of the common problem that occur when declaring filters. It is
|
||||
recommended that you read this as it provides a more complete understanding of
|
||||
how filters work.
|
||||
|
||||
|
||||
Filter ``name`` and ``lookup_expr`` not configured
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While ``name`` and ``lookup_expr`` are optional, it is recommended that you specify
|
||||
them. By default, if ``name`` is not specified, the filter's name on the
|
||||
filterset class will be used. Additionally, ``lookup_expr`` defaults to
|
||||
``exact``. The following is an example of a misconfigured price filter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
price__gt = django_filters.NumberFilter()
|
||||
|
||||
The filter instance will have a field name of ``price__gt`` and an ``exact``
|
||||
lookup type. Under the hood, this will incorrectly be resolved as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Produce.objects.filter(price__gt__exact=value)
|
||||
|
||||
The above will most likely generate a ``FieldError``. The correct configuration
|
||||
would be:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
price__gt = django_filters.NumberFilter(name='price', lookup_expr='gt')
|
||||
|
||||
|
||||
Missing ``lookup_expr`` for text search filters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's quite common to forget to set the lookup expression for :code:`CharField`
|
||||
and :code:`TextField` and wonder why a search for "foo" does not return results
|
||||
for "foobar". This is because the default lookup type is ``exact``, but you
|
||||
probably want to perform an ``icontains`` lookup.
|
||||
|
||||
|
||||
Filter and lookup expression mismatch (in, range, isnull)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's not always appropriate to directly match a filter to its model field's
|
||||
type, as some lookups expect different types of values. This is a commonly
|
||||
found issue with ``in``, ``range``, and ``isnull`` lookups. Let's look
|
||||
at the following product model:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Product(models.Model):
|
||||
category = models.ForeignKey(Category, null=True)
|
||||
|
||||
Given that ``category`` is optional, it's reasonable to want to enable a search
|
||||
for uncategorized products. The following is an incorrectly configured
|
||||
``isnull`` filter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
uncategorized = django_filters.NumberFilter(name='category', lookup_expr='isnull')
|
||||
|
||||
So what's the issue? While the underlying column type for ``category`` is an
|
||||
integer, ``isnull`` lookups expect a boolean value. A ``NumberFilter`` however
|
||||
only validates numbers. Filters are not `'expression aware'` and won't change
|
||||
behavior based on their ``lookup_expr``. You should use filters that match the
|
||||
data type of the lookup expression `instead` of the data type underlying the
|
||||
model field. The following would correctly allow you to search for both
|
||||
uncategorized products and products for a set of categories:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class NumberInFilter(django_filters.BaseInFilter, django_filters.NumberFilter):
|
||||
pass
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
categories = NumberInFilter(name='category', lookup_expr='in')
|
||||
uncategorized = django_filters.BooleanFilter(name='category', lookup_expr='isnull')
|
||||
|
||||
More info on constructing ``in`` and ``range`` csv :ref:`filters <base-in-filter>`.
|
|
@ -81,82 +81,6 @@ For Django version 1.8, transformed expressions are not supported.
|
|||
.. _`lookup reference`: https://docs.djangoproject.com/en/dev/ref/models/lookups/#module-django.db.models.lookups
|
||||
|
||||
|
||||
Common declarative problems
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Below are some of the common problem that occur when declaring filters. It is
|
||||
recommended that you do read this as it provides a more complete understanding
|
||||
on how filters work.
|
||||
|
||||
|
||||
Filter ``name`` and ``lookup_expr`` not configured
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
While ``name`` and ``lookup_expr`` are optional, it is recommended that you specify
|
||||
them. By default, if ``name`` is not specified, the filter's name on the
|
||||
filterset class will be used. Additionally, ``lookup_expr`` defaults to
|
||||
``exact``. The following is an example of a misconfigured price filter::
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
price__gt = django_filters.NumberFilter()
|
||||
|
||||
The filter instance will have a field name of ``price__gt`` and an ``exact``
|
||||
lookup type. Under the hood, this will incorrectly be resolved as::
|
||||
|
||||
Produce.objects.filter(price__gt__exact=value)
|
||||
|
||||
The above will most likely generate a ``FieldError``. The correct configuration
|
||||
would be::
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
price__gt = django_filters.NumberFilter(name='price', lookup_expr='gt')
|
||||
|
||||
|
||||
Missing ``lookup_expr`` for text search filters
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
It's quite common to forget to set the lookup expression for :code:`CharField`
|
||||
and :code:`TextField` and wonder why a search for "foo" does not return results
|
||||
for "foobar". This is because the default lookup type is ``exact``, but you
|
||||
probably want to perform an ``icontains`` lookup.
|
||||
|
||||
|
||||
Filter and lookup expression mismatch (in, range, isnull)
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
It's not always appropriate to directly match a filter to its model field's
|
||||
type, as some lookups expect different types of values. This is a commonly
|
||||
found issue with ``in``, ``range``, and ``isnull`` lookups. Let's look
|
||||
at the following product model::
|
||||
|
||||
class Product(models.Model):
|
||||
category = models.ForeignKey(Category, null=True)
|
||||
|
||||
Given that ``category`` is optional, it's reasonable to want to enable a search
|
||||
for uncategorized products. The following is an incorrectly configured
|
||||
``isnull`` filter::
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
uncategorized = django_filters.NumberFilter(name='category', lookup_expr='isnull')
|
||||
|
||||
So what's the issue? While the underlying column type for ``category`` is an
|
||||
integer, ``isnull`` lookups expect a boolean value. A ``NumberFilter`` however
|
||||
only validates numbers. Filters are not `'expression aware'` and won't change
|
||||
behavior based on their ``lookup_expr``. You should use filters that match the
|
||||
data type of the lookup expression `instead` of the data type underlying model
|
||||
field. The following would correctly allow you to search for both uncategorized
|
||||
products and products for a set of categories::
|
||||
|
||||
class NumberInFilter(django_filters.BaseInFilter, django_filters.NumberFilter):
|
||||
pass
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
categories = NumberInFilter(name='category', lookup_expr='in')
|
||||
uncategorized = django_filters.BooleanFilter(name='category', lookup_expr='isnull')
|
||||
|
||||
More info on constructing IN and RANGE csv :ref:`filters <base-in-filter>`.
|
||||
|
||||
|
||||
Generating filters with Meta.fields
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ do this.
|
|||
guide/install
|
||||
guide/usage
|
||||
guide/rest_framework
|
||||
guide/tips
|
||||
guide/migration
|
||||
|
||||
.. toctree::
|
||||
|
|
Loading…
Reference in New Issue