-
Notifications
You must be signed in to change notification settings - Fork 755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework validation, add queryset filter method #788
Changes from 7 commits
4d5f5b9
2626e4c
842d253
051694a
f575dd7
1f9d973
4b74f07
d56080b
16e833e
c2cb9b2
b9f9d27
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,9 +11,7 @@ Meta options | |
- :ref:`fields <fields>` | ||
- :ref:`exclude <exclude>` | ||
- :ref:`form <form>` | ||
- :ref:`together <together>` | ||
- :ref:`filter_overrides <filter_overrides>` | ||
- :ref:`strict <strict>` | ||
|
||
|
||
.. _model: | ||
|
@@ -101,26 +99,6 @@ form class from which ``FilterSet.form`` will subclass. This works similar to | |
the ``form`` option on a ``ModelAdmin.`` | ||
|
||
|
||
.. _together: | ||
|
||
Group fields with ``together`` | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
The inner ``Meta`` class also takes an optional ``together`` argument. This | ||
is a list of lists, each containing field names. For convenience can be a | ||
single list/tuple when dealing with a single set of fields. Fields within a | ||
field set must either be all or none present in the request for | ||
``FilterSet.form`` to be valid:: | ||
|
||
import django_filters | ||
|
||
class ProductFilter(django_filters.FilterSet): | ||
class Meta: | ||
model = Product | ||
fields = ['price', 'release_date', 'rating'] | ||
together = ['rating', 'price'] | ||
|
||
|
||
.. _filter_overrides: | ||
|
||
Customise filter generation with ``filter_overrides`` | ||
|
@@ -149,39 +127,28 @@ This is a map of model fields to filter classes with options:: | |
}, | ||
} | ||
|
||
Overriding ``FilterSet`` methods | ||
-------------------------------- | ||
|
||
.. _strict: | ||
When overriding classmethods, calling ``super(MyFilterSet, cls)`` may result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What doesn't look right here? The example is intended to show how you would accidentally generate a |
||
in a ``NameError`` exception. This is due to the ``FilterSetMetaclass`` calling | ||
these classmethods before the ``FilterSet`` class has been fully created. | ||
There are two recommmended workarounds: | ||
|
||
Handling validation errors with ``strict`` | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1. If using python 3.6 or newer, use the argumentless ``super()`` syntax. | ||
2. For older versions of python, use an intermediate class. Ex:: | ||
|
||
The ``strict`` option determines the filterset's behavior when filters fail to validate. Example use: | ||
class Intermediate(django_filters.FilterSet): | ||
|
||
.. code-block:: python | ||
|
||
from django_filters import FilterSet, STRICTNESS | ||
@classmethod | ||
def method(cls, arg): | ||
super(Intermediate, cls).method(arg) | ||
... | ||
|
||
class ProductFilter(FilterSet): | ||
class ProductFilter(Intermediate): | ||
class Meta: | ||
model = Product | ||
fields = ['name', 'release_date'] | ||
strict = STRICTNESS.RETURN_NO_RESULTS | ||
|
||
Currently, there are three different behaviors: | ||
|
||
- ``STRICTNESS.RETURN_NO_RESULTS`` (default) This returns an empty queryset. The | ||
filterset form can then be rendered to display the input errors. | ||
- ``STRICTNESS.IGNORE`` Instead of returning an empty queryset, invalid filters | ||
effectively become a noop. Valid filters are applied to the queryset however. | ||
- ``STRICTNESS.RAISE_VALIDATION_ERROR`` This raises a ``ValidationError`` for | ||
all invalid filters. This behavior is generally useful with APIs. | ||
|
||
If the ``strict`` option is not provided, then the filterset will default to the | ||
value of the ``FILTERS_STRICTNESS`` setting. | ||
|
||
|
||
Overriding ``FilterSet`` methods | ||
-------------------------------- | ||
fields = ['...'] | ||
|
||
``filter_for_lookup()`` | ||
~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
@@ -212,4 +179,4 @@ filters for a model field, you can override ``filter_for_lookup()``. Ex:: | |
return django_filters.DateRangeFilter, {} | ||
|
||
# use default behavior otherwise | ||
return super(ProductFilter, cls).filter_for_lookup(f, lookup_type) | ||
return super().filter_for_lookup(f, lookup_type) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one does though. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I noticed that even if I do not want to raise exception here, then it is not raised, but queryset returned without filtering. I guess in case if invalid filterset and do not raise exception it should return
qs.none()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It keeps the partial queryset, yet - I think this is tested for in https://github.com/carltongibson/django-filter/pull/788/files#diff-b18add7202661e9eacece0aded8e619bR301.