Merge pull request #554 from rpkilby/docs-changes
Documentation updates
This commit is contained in:
commit
677b48f145
|
@ -12,9 +12,9 @@ Full documentation on `read the docs`_.
|
|||
Requirements
|
||||
------------
|
||||
|
||||
* Python 2.7, 3.3, 3.4, 3.5
|
||||
* Django 1.8, 1.9, 1.10
|
||||
* DRF 3.3 (Django 1.8 only), 3.4
|
||||
* **Python**: 2.7, 3.3, 3.4, 3.5
|
||||
* **Django**: 1.8, 1.9, 1.10
|
||||
* **DRF**: 3.4, 3.5
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,67 @@
|
|||
======================
|
||||
Running the Test Suite
|
||||
======================
|
||||
|
||||
The easiest way to run the django-filter tests is to check out the source
|
||||
code and create a virtualenv where you can install the test dependencies.
|
||||
Django-filter uses a custom test runner to configure the environment, so a
|
||||
wrapper script is available to set up and run the test suite.
|
||||
|
||||
.. note::
|
||||
|
||||
The following assumes you have `virtualenv`__ and `git`__ installed.
|
||||
|
||||
__ https://virtualenv.pypa.io/en/stable/
|
||||
__ https://git-scm.com
|
||||
|
||||
Clone the repository
|
||||
--------------------
|
||||
|
||||
Get the source code using the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone https://github.com/carltongibson/django-filter.git
|
||||
|
||||
Switch to the django-filter directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd django-filter
|
||||
|
||||
Set up the virtualenv
|
||||
---------------------
|
||||
|
||||
Create a new virtualenv to run the test suite in:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ virtualenv venv
|
||||
|
||||
Then activate the virtualenv and install the test requirements:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ source venv/bin/activate
|
||||
$ pip install -r requirements/test.txt
|
||||
|
||||
Execute the test runner
|
||||
-----------------------
|
||||
|
||||
Run the tests with the runner script:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python runtests.py
|
||||
|
||||
|
||||
Test all supported versions
|
||||
---------------------------
|
||||
|
||||
You can also use the excellent tox testing tool to run the tests against all
|
||||
supported versions of Python and Django. Install tox, and then simply run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install tox
|
||||
$ tox
|
|
@ -0,0 +1,33 @@
|
|||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
Django-filter can be installed from PyPI with tools like ``pip``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install django-filter
|
||||
|
||||
Then add ``'django_filters'`` to your ``INSTALLED_APPS``.
|
||||
|
||||
.. note::
|
||||
|
||||
django-filter provides *some* localization for *some* languages. If you do
|
||||
not need these translations (or would rather provide your own), then it is
|
||||
unnecessary to add django-filter to the ``INSTALLED_APPS`` setting.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Django-filter is tested against all supported versions of Python and `Django`__,
|
||||
as well as the latest versions of Django REST Framework (`DRF`__).
|
||||
|
||||
__ https://www.djangoproject.com/download/
|
||||
__ http://www.django-rest-framework.org/
|
||||
|
||||
|
||||
|
||||
* **Python**: 2.7, 3.3, 3.4, 3.5
|
||||
* **Django**: 1.8, 1.9, 1.10
|
||||
* **DRF**: 3.4, 3.5
|
|
@ -1,3 +1,4 @@
|
|||
================
|
||||
Migrating to 1.0
|
||||
================
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
Django Rest Framework
|
||||
=====================
|
||||
====================
|
||||
Integration with DRF
|
||||
====================
|
||||
|
||||
Integration with `Django Rest Framework`__ is provided through a DRF-specific ``FilterSet`` and a `filter backend`__. These may be found in the ``rest_framework`` sub-package.
|
||||
|
||||
|
@ -72,8 +73,8 @@ To enable filtering with a ``FilterSet``, add it to the ``filter_class`` paramet
|
|||
filter_class = ProductFilter
|
||||
|
||||
|
||||
Specifying ``filter_fields``
|
||||
----------------------------
|
||||
Using the ``filter_fields`` shortcut
|
||||
------------------------------------
|
||||
|
||||
You may bypass creating a ``FilterSet`` by instead adding ``filter_fields`` to your view class. This is equivalent to creating a FilterSet with just :ref:`Meta.fields <fields>`.
|
||||
|
||||
|
@ -168,4 +169,4 @@ If you are using DRF's browsable API or admin API you may also want to install `
|
|||
|
||||
With crispy forms installed and added to Django's ``INSTALLED_APPS``, the browsable API will present a filtering control for ``DjangoFilterBackend``, like so:
|
||||
|
||||
.. image:: img/form.png
|
||||
.. image:: ../assets/form.png
|
|
@ -0,0 +1,215 @@
|
|||
==================
|
||||
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>`.
|
||||
|
||||
|
||||
Filtering by empty values
|
||||
-------------------------
|
||||
|
||||
There are a number of cases where you may need to filter by empty or null
|
||||
values. The following are some common solutions to these problems:
|
||||
|
||||
|
||||
Filtering by null values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
As explained in the above "Filter and lookup expression mismatch" section, a
|
||||
common problem is how to correctly filter by null values on a field.
|
||||
|
||||
Solution 1: Using a ``BooleanFilter`` with ``isnull``
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Using ``BooleanFilter`` with an ``isnull`` lookup is a builtin solution used by
|
||||
the FilterSet's automatic filter generation. To do this manually, simply add:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
uncategorized = django_filters.BooleanFilter(name='category', lookup_expr='isnull')
|
||||
|
||||
.. note::
|
||||
|
||||
Remember that the filter class is validating the input value. The underlying
|
||||
type of the mode field is not relevant here.
|
||||
|
||||
You may also reverse the logic with the ``exclude`` parameter.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
has_category = django_filters.BooleanFilter(name='category', lookup_expr='isnull', exclude=True)
|
||||
|
||||
Solution 2: Using ``ChoiceFilter``'s null choice
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
If you're using a ChoiceFilter, you may also filter by null values by enabling
|
||||
the ``null_label`` parameter. More details in the ``ChoiceFilter`` reference
|
||||
:ref:`docs <choice-filter>`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
category = django_filters.ModelChoiceFilter(
|
||||
name='category', lookup_expr='isnull',
|
||||
null_label='Uncategorized',
|
||||
queryset=Category.objects.all(),
|
||||
)
|
||||
|
||||
Solution 3: Combining fields w/ ``MultiValueField``
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
An alternative approach is to use Django's ``MultiValueField`` to manually add
|
||||
in a ``BooleanField`` to handle null values. Proof of concept:
|
||||
https://github.com/carltongibson/django-filter/issues/446
|
||||
|
||||
|
||||
Filtering by an empty string
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's not currently possible to filter by an empty string, since empty values are
|
||||
interpreted as a skipped filter.
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET http://localhost/api/my-model?myfield=
|
||||
|
||||
Solution 1: Magic values
|
||||
""""""""""""""""""""""""
|
||||
|
||||
You can override the ``filter()`` method of a filter class to specifically check
|
||||
for magic values. This is similar to the ``ChoiceFilter``'s null value handling.
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET http://localhost/api/my-model?myfield=EMPTY
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyCharFilter(filters.CharFilter):
|
||||
empty_value = 'EMPTY'
|
||||
|
||||
def filter(self, qs, value):
|
||||
if value != self.empty_value:
|
||||
return super(MyCharFilter, self).filter(qs, value)
|
||||
|
||||
qs = self.get_method(qs)(**{'%s__%s' % (self.name, self.lookup_expr): ""})
|
||||
return qs.distinct() if self.distinct else qs
|
||||
|
||||
|
||||
Solution 2: Empty string filter
|
||||
"""""""""""""""""""""""""""""""
|
||||
|
||||
It would also be possible to create an empty value filter that exhibits the same
|
||||
behavior as an ``isnull`` filter.
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET http://localhost/api/my-model?myfield__isempty=false
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
|
||||
class EmptyStringFilter(filters.BooleanFilter):
|
||||
def filter(self, qs, value):
|
||||
if value in EMPTY_VALUES:
|
||||
return qs
|
||||
|
||||
exclude = self.exclude ^ (value is False)
|
||||
method = qs.exclude if exclude else qs.filter
|
||||
|
||||
return method(**{self.name: ""})
|
||||
|
||||
|
||||
class MyFilterSet(filters.FilterSet):
|
||||
myfield__isempty = EmptyStringFilter(name='myfield')
|
||||
|
||||
class Meta:
|
||||
model = MyModel
|
|
@ -1,5 +1,6 @@
|
|||
Using django-filter
|
||||
===================
|
||||
===============
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
Django-filter provides a simple way to filter down a queryset based on
|
||||
parameters a user provides. Say we have a ``Product`` model and we want to let
|
||||
|
@ -80,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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -223,7 +148,7 @@ default filters for all the models fields of the same kind using
|
|||
models.BooleanField: {
|
||||
'filter_class': django_filters.BooleanFilter,
|
||||
'extra': lambda f: {
|
||||
'widget': 'forms.CheckboxInput',
|
||||
'widget': forms.CheckboxInput,
|
||||
},
|
||||
},
|
||||
}
|
|
@ -7,18 +7,28 @@ the more mundane bits of view code. Specifically, it allows users to filter
|
|||
down a queryset based on a model's fields, displaying the form to let them
|
||||
do this.
|
||||
|
||||
Contents:
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: User Guide
|
||||
|
||||
guide/install
|
||||
guide/usage
|
||||
guide/rest_framework
|
||||
guide/tips
|
||||
guide/migration
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Reference Documentation
|
||||
|
||||
install
|
||||
usage
|
||||
rest_framework
|
||||
ref/filterset
|
||||
ref/filters
|
||||
ref/fields
|
||||
ref/widgets
|
||||
ref/settings
|
||||
migration
|
||||
tests
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Developer Documentation
|
||||
|
||||
dev/tests
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
Installing django-filter
|
||||
------------------------
|
||||
|
||||
Install with pip:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install django-filter
|
||||
|
||||
And then add ``'django_filters'`` to your ``INSTALLED_APPS``.
|
||||
|
||||
.. note::
|
||||
|
||||
django-filter provides *some* localization for *some* languages. If you do
|
||||
not need these translations (or would rather provide your own), then it is
|
||||
unnecessary to add django-filter to the ``INSTALLED_APPS`` setting.
|
|
@ -1,5 +1,6 @@
|
|||
Fields Reference
|
||||
================
|
||||
===============
|
||||
Field Reference
|
||||
===============
|
||||
|
||||
``IsoDateTimeField``
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -10,7 +11,9 @@ Defines a class level attribute ``ISO_8601`` as constant for the format.
|
|||
|
||||
Sets ``input_formats = [ISO_8601]`` — this means that by default ``IsoDateTimeField`` will **only** parse ISO 8601 formated dates.
|
||||
|
||||
You may set ``input_formats`` to your list of required formats as per the `DateTimeField Docs`_, using the ``ISO_8601`` class level attribute to specify the ISO 8601 format. ::
|
||||
You may set ``input_formats`` to your list of required formats as per the `DateTimeField Docs`_, using the ``ISO_8601`` class level attribute to specify the ISO 8601 format.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
f = IsoDateTimeField()
|
||||
f.input_formats = [IsoDateTimeField.ISO_8601] + DateTimeField.input_formats
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
================
|
||||
Filter Reference
|
||||
================
|
||||
|
||||
|
@ -191,6 +192,8 @@ This filter matches UUID values, used with ``models.UUIDField`` by default.
|
|||
This filter matches a boolean, either ``True`` or ``False``, used with
|
||||
``BooleanField`` and ``NullBooleanField`` by default.
|
||||
|
||||
.. _choice-filter:
|
||||
|
||||
``ChoiceFilter``
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
FilterSet Guide
|
||||
===============
|
||||
=================
|
||||
FilterSet Options
|
||||
=================
|
||||
|
||||
This document provides a guide on using additional FilterSet features.
|
||||
|
||||
|
@ -9,7 +10,6 @@ Meta options
|
|||
- :ref:`model <model>`
|
||||
- :ref:`fields <fields>`
|
||||
- :ref:`exclude <exclude>`
|
||||
- :ref:`order_by <order-by>`
|
||||
- :ref:`form <form>`
|
||||
- :ref:`together <together>`
|
||||
- filter_overrides
|
||||
|
@ -91,40 +91,6 @@ declared directly on the ``FilterSet``.
|
|||
exclude = ['password']
|
||||
|
||||
|
||||
.. _order-by:
|
||||
|
||||
Ordering using ``order_by``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can allow the user to control ordering by providing the
|
||||
``order_by`` argument in the Filter's Meta class. ``order_by`` can be either a
|
||||
``list`` or ``tuple`` of field names, in which case those are the options, or
|
||||
it can be a ``bool`` which, if True, indicates that all fields that
|
||||
the user can filter on can also be sorted on. An example of ordering using a list::
|
||||
|
||||
import django_filters
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
price = django_filters.NumberFilter(lookup_expr='lt')
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['price', 'release_date']
|
||||
order_by = ['price']
|
||||
|
||||
If you want to control the display of items in ``order_by``, you can set it to
|
||||
a list or tuple of 2-tuples in the format ``(field_name, display_name)``.
|
||||
This lets you override the displayed names for your ordering fields::
|
||||
|
||||
order_by = (
|
||||
('name', 'Company Name'),
|
||||
('average_rating', 'Stars'),
|
||||
)
|
||||
|
||||
Note that the default query parameter name used for ordering is ``o``. You
|
||||
can override this by setting an ``order_by_field`` attribute on the
|
||||
``FilterSet``'s Meta class to the string value you would like to use.
|
||||
|
||||
|
||||
.. _form:
|
||||
|
||||
Custom Forms using ``form``
|
||||
|
@ -201,29 +167,3 @@ filters for a model field, you can override ``filter_for_lookup()``. Ex::
|
|||
|
||||
# use default behavior otherwise
|
||||
return super(ProductFilter, cls).filter_for_lookup(f, lookup_type)
|
||||
|
||||
|
||||
``get_ordering_field()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to use a custom widget, or in any other way override the ordering
|
||||
field you can override the ``get_ordering_field()`` method on a ``FilterSet``.
|
||||
This method just needs to return a Form Field.
|
||||
|
||||
Ordering on multiple fields, or other complex orderings can be achieved by
|
||||
overriding the ``FilterSet.get_order_by()`` method. This is passed the selected
|
||||
``order_by`` value, and is expected to return an iterable of values to pass to
|
||||
``QuerySet.order_by``. For example, to sort a ``User`` table by last name, then
|
||||
first name::
|
||||
|
||||
class UserFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
order_by = (
|
||||
('username', 'Username'),
|
||||
('last_name', 'Last Name')
|
||||
)
|
||||
|
||||
def get_order_by(self, order_value):
|
||||
if order_value == 'last_name':
|
||||
return ['last_name', 'first_name']
|
||||
return super(UserFilter, self).get_order_by(order_value)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
.. _ref-settings:
|
||||
|
||||
==================
|
||||
Available Settings
|
||||
Settings Reference
|
||||
==================
|
||||
|
||||
Here is a list of all available settings of django-filters and their
|
||||
|
@ -94,6 +92,6 @@ For example, you could add verbose output for "exact" lookups.
|
|||
FILTERS_STRICTNESS
|
||||
------------------
|
||||
|
||||
DEFAULT: ``STRICTNESS.RETURN_NO_RESULTS``
|
||||
Default: ``STRICTNESS.RETURN_NO_RESULTS``
|
||||
|
||||
Set the global default for FilterSet :ref:`strictness <strict>`.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
================
|
||||
Widget Reference
|
||||
================
|
||||
|
||||
|
@ -29,7 +30,9 @@ placeholders:
|
|||
|
||||
This widget converts its input into Python's True/False values. It will convert
|
||||
all case variations of ``True`` and ``False`` into the internal Python values.
|
||||
To use it, pass this into the ``widgets`` argument of the ``BooleanFilter``::
|
||||
To use it, pass this into the ``widgets`` argument of the ``BooleanFilter``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
active = BooleanFilter(widget=BooleanWidget())
|
||||
|
||||
|
@ -53,6 +56,8 @@ This widget is used with ``RangeFilter`` and its subclasses. It generates two
|
|||
form input elements which generally act as start/end values in a range.
|
||||
Under the hood, it is django's ``forms.TextInput`` widget and excepts
|
||||
the same arguments and values. To use it, pass it to ``widget`` argument of
|
||||
a ``RangeField``::
|
||||
a ``RangeField``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
date_range = DateFromToRangeFilter(widget=RangeWidget(attrs={'placeholder': 'YYYY/MM/DD'}))
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
Running the django-filter tests
|
||||
===============================
|
||||
|
||||
The easiest way to run the django-filter tests is to check out the source
|
||||
code into a virtualenv, where you can install the test dependencies.
|
||||
django-filter uses a custom test runner to locate all of the tests, so a
|
||||
wrapper script is available to set up and run the test suite.
|
||||
|
||||
.. note::
|
||||
|
||||
The following assumes you have `virtualenv`__ and `git`__ installed.
|
||||
|
||||
__ http://www.virtualenv.org
|
||||
__ http://git-scm.com
|
||||
|
||||
Set up a virtualenv for the test suite
|
||||
--------------------------------------
|
||||
|
||||
Run the following to create a new virtualenv to run the test suite in::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
virtualenv django-filter-tests
|
||||
cd django-filter-tests
|
||||
. bin/activate
|
||||
|
||||
Get a copy of django-filter
|
||||
---------------------------
|
||||
|
||||
Get the django-filter source code using the following command::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/alex/django-filter.git
|
||||
|
||||
Switch to the django-filter directory::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd django-filter
|
||||
|
||||
Install the test dependencies
|
||||
-----------------------------
|
||||
|
||||
Run the following to install the test dependencies within the
|
||||
virutalenv::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -r requirements/test.txt
|
||||
|
||||
Run the django-filter tests::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python runtests.py
|
||||
|
||||
|
||||
Testing all supported versions
|
||||
------------------------------
|
||||
|
||||
You can also use the excellent tox testing tool to run the tests against all supported versions of
|
||||
Python and Django. Install tox globally, and then simply run::
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox
|
||||
|
Loading…
Reference in New Issue