Django URL Filter¶
Contents¶
Usage¶
Vanilla¶
In its simplest form, Django URL Filter usage resolves around FilterSet
.
They can be used manually:
from django import forms
from url_filter.filter import Filter
from url_filter.filtersets import FilterSet
class ProfileFilterSet(FilterSet):
lives_in_country = Filter(form_field=forms.CharField())
class UserFilterSet(FilterSet):
username = Filter(form_field=forms.CharField(), lookups=['exact'])
email = Filter(form_field=forms.CharField())
joined = Filter(form_field=forms.DateField())
profile = ProfileFilterSet()
query = QueryDict(
'email__contains=gmail'
'&joined__year=2015'
'&profile__lives_in_country__iexact=us'
)
fs = UserFilterSet(data=query, queryset=User.objects.all())
filtered_users = fs.filter()
Notable things to mention from above:
FilterSet
can be used as aFilter
within anotherFilterSet
hence allowing filtering by related models.form_field
is used to validate the filter value. Each lookup however can overwrite validation. For exampleyear
lookup will useIntegerField
rather thenDateField
.Filter
can restrict allowed lookups for that field by usinglookup
parameter
Django¶
Instead of manually creating FilterSet
, Django URL Filter comes with
ModelFilterSet
which greatly simplifies the task:
from django import forms
from url_filter.filtersets import ModelFilterSet
class UserFilterSet(ModelFilterSet):
class Meta(object):
model = User
fields = ['username', 'email', 'joined', 'profile']
Notable things:
fields
can actually be completely omitted. In that caseFilterSet
will use all fields available in the model, including related fields.filters can be manually overwritten when custom behavior is required:
class UserFilterSet(ModelFilterSet): username = Filter(form_field=forms.CharField(max_length=15)) class Meta(object): model = User fields = ['username', 'email', 'joined', 'profile']
SQLAlchemy¶
SQLAlchemy works very similar to how Django backend works. For example:
from django import forms
from url_filter.backend.sqlalchemy import SQLAlchemyFilterBackend
from url_filter.filtersets.sqlalchemy import SQLAlchemyModelFilterSet
class UserFilterSet(SQLAlchemyModelFilterSet):
filter_backend_class = SQLAlchemyFilterBackend
class Meta(object):
model = User # this model should be SQLAlchemy model
fields = ['username', 'email', 'joined', 'profile']
fs = UserFilterSet(data=QueryDict(), queryset=session.query(User))
fs.filter()
Notable things:
- this works exactly same as
ModelFitlerSet
so refer above for some of general options. filter_backend_class
must be provided since otherwiseDjangoFilterBackend
will be used which will obviously not work with SQLAlchemy models.queryset
given to the queryset should be SQLAlchemy query object.
Integrations¶
Django URL Filters tries to be usage-agnostic and does not assume
how FilterSet
is being used in the application. It does however
ship with some common integrations to simplify common workflows.
Django REST Framework¶
Django URL Filter can rather easily be integrated with DRF. For that, a DRF filter backend is implemented and can be used in settings:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'url_filter.integrations.drf.DjangoFilterBackend',
]
}
or manually set in the viewset:
class MyViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = [DjangoFilterBackend]
filter_fields = ['field1', 'field2']
Note in the example above, fields to be filtered on are explicitly
specified in the filter_fields
attribute. Alternatively if more
control over FilterSet
is required, it can be set explicitly:
class MyFilterSet(FilterSet):
pass
class MyViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = [DjangoFilterBackend]
filter_class = MyFilterSet
Backends¶
FilterSet
by itself is decoupled from the actual filtering
of the queryset. Backend can be swapped by using filter_backend_class
:
class FooFilterSet(FilterSet):
filter_backend_class = MyFilterBackend
Note
Currently only DjangoFilterBackend
is implemented which uses
Django ORM however more backends are planned for.
Big Picture¶
This document explains all of the concepts used in Django URL Filter in context hence providing a “big picture” of how it works.
Basics¶
In order to filter any data, this library breaks the process to 3 phases:
- Parse the URL querystring into
LookupConfig
- Loop throught all the configs and generate
FilterSpec
when possible - Use the list of specs to actually filter data
And here is a bit more information about each phase.
Parsing¶
Fundamentally a querystring is a collection of key-pairs. As such, this data is natually flat and is usually represented as a simple dictionary:
?foo=bar&happy=rainbows => {
'foo': 'bar',
'happy': 'rainbows',
}
Note
Technically this is not 100% true since key
can be repeated which is why Django uses QueryDict
but for
the purposes of this discussion, lets assume no duplicate keys
are present.
The filtering however is not flat. Each querystring key can be nested
when using nested FilterSet
and in addition it can optionally
contain lookup. For example:
?foo=bar
?foo__contains=bar
?foo__nested=bar
?foo__nested__contains=bar
?foo__nested__othernested=bar
?foo__nested__othernested__contains=bar
In order to accomodate the nested structure of querystring keys, Django URL Filter parses all querystring key-value pairs to nested dictionaries. For example:
?foo__nested__othernested=bar => {
'foo': {
'nested': {
'othernested': 'bar'
}
}
}
?foo__nested__othernested__contains=bar => {
'foo': {
'nested': {
'othernested': {
'contains': 'bar'
}
}
}
}
That is essentially what LookupConfig
stores. Since these dictionaries
are flat (each dictionaty has at most one key), it also provides some utility
properties for dealing with such data. You can refer to the
url_filter.utils.LookupConfig
API documentation for more
information.
Filter Specification¶
As mentioned in README, Django URL Filter decouples parsing
of querystring and filtering. It achieves that by constructing filter
specifications which have all necessary information to filter data
without actually filtering data. Thats what FilterSpec
is.
It stores 3 required pieces of information on how to filter data:
- Which attribute to filter on. Since models can be related by attributes related models, this actually ends up being a list of attributes which we call components.
- Lookup to use to filter data. This specifies how the value should be
compared while doing filtering. Example is
exact
,contains
. Currenlty only lookups from Django ORM are supported. - If the filter is negated. For example to filter when username is
'foo'
to filter when username is not'foo'
.
Filtering¶
Since filtering is decoupled from the FilterSet
, the filtering honors
all go to a specified filter backend. The backend is very simple.
It takes a list of filter specifications and a data to filter and its
job is to filter that data as specified in the specifications.
Note
Currently we only support Django ORM and SQLAlchemy filter backends but you can imagine that any backend can be implemented. Eventually filter backends can be added for flat data-structures like filtering a vanilla Python lists or even more exotic sources like Mongo, Redis, etc.
Steps¶
Above information hopefully puts things in perspective and here is more detailed step-by-step guide what Django URL Filter does behind the scenes:
FilterSet
is instantiated with querystring data as well as querystring to filter.FilterSet
is asked to filter given data viafilter
method which kicks in all the steps below.FilterSet
finds all filters it is capable of Filtering viaget_filters
. This is where custom filtersets can hook into to do custom stuff like extracting filters from a Django model.FilterSet
binds all child filters to itself viabind
. This practically setsparent
andname
.- Root
FilterSet
loops through all querystring pairs and generatesLookupConfig
for all of them. - Root
FilterSet
loops through all generated configs and attemps to find appropriate filter to use to generate a spec fo the given config. The matching happens by the first key in theLookupConfig
dict. If that key is found in available filters, that filer is used and otherwise that config is skipped. This is among the reasons whyLookupConfig
is used since it allows this step to be very simple. - If appropriate filter is found, it is passed nested config to the child filter which then goes through very similar process as in previous step until it gets to a leaf filter.
- Leaf
Filter
gets the config. In then checks if the config is still nested. For example if the config is simply a value (e.g.'bar'
) or is still a dictionary (e.g.{'contains': 'bar'}
). If the config is just a value, it then uses a default lookup for that filter as provided indefault_lookup
parameter when instantiatingFilter
. If the config is a dictionary, it makes sure that it is a valid lookup config (e.g. its not{'rainbows': {'contains': 'bar'}}
since it would not know what to do withrainbows
since it is not a valid lookup value). - Now that
Filter
validated the lookup itself, it cleans the actual filter value by using eitherform_field
as passed as parameter when instantiatingFilter
or by using loopup overwrite. Overwrites are necessary for more exotic lookups likein
oryear
since they need to validate data in a different way. - If the value is valid, then the leaf filter constructs a
FilterSpec
since it has all the necessary information to do that - 1) all filter component names from all ancestors (e.g. all attributes which should be accessed on the queryset to get to the value to be filtered on); 2) the actual filter value and 3) if the filter is negated. - At this point, root
FilterSpec
will get theFilterSpec
as bubbled up from the leaf filter. If anyValidationError
exceptions are raised, then depending onstrict_mode
, it will either ignores errors or will propagate them up to the caller of the filterset. - Once all specs are collected from all the querystring key-value-pairs,
root
FilterSet
instantiates a filter backend and passes it all the specs. - Finally root
FilterSet
uses the filter backend to filter given queryset and returns the results to the user.
Some important things to note:
- Root
FilterSet
does all the looping over querystring data and generated configurations. - Children filters of a root
FilterSet
are only responsible for generatingFilterSpec
and in the process validating the data.
History¶
0.2.0 (2015-09-12)¶
Added SQLAlchemy support.
FilterSet
instances have much more useful__repr__
which shows all filters at a glance. For example:>>> PlaceFilterSet() PlaceFilterSet() address = Filter(form_field=CharField, lookups=ALL, default_lookup="exact", is_default=False) id = Filter(form_field=IntegerField, lookups=ALL, default_lookup="exact", is_default=True) name = Filter(form_field=CharField, lookups=ALL, default_lookup="exact", is_default=False) restaurant = RestaurantFilterSet() serves_hot_dogs = Filter(form_field=BooleanField, lookups=ALL, default_lookup="exact", is_default=False) serves_pizza = Filter(form_field=BooleanField, lookups=ALL, default_lookup="exact", is_default=False) waiter = WaiterFilterSet() id = Filter(form_field=IntegerField, lookups=ALL, default_lookup="exact", is_default=True) name = Filter(form_field=CharField, lookups=ALL, default_lookup="exact", is_default=False)
0.1.1 (2015-09-06)¶
- Fixed installation issue where not all subpackages were installed.
0.1.0 (2015-08-30)¶
- First release on PyPI.
url_filter¶
url_filter package¶
Subpackages¶
url_filter.backends package¶
-
class
url_filter.backends.django.
DjangoFilterBackend
(queryset, context=None)[source]¶ Bases:
url_filter.backends.base.BaseFilterBackend
-
excludes
¶
-
includes
¶
-
supported_lookups
= set([u'gt', u'year', u'month', u'isnull', u'second', u'week_day', u'in', u'regex', u'gte', u'contains', u'lt', u'startswith', u'iendswith', u'icontains', u'iexact', u'exact', u'day', u'minute', u'hour', u'iregex', u'endswith', u'range', u'istartswith', u'lte'])¶
-
-
class
url_filter.backends.sqlalchemy.
SQLAlchemyFilterBackend
(*args, **kwargs)[source]¶ Bases:
url_filter.backends.base.BaseFilterBackend
-
supported_lookups
= set([u'startswith', u'gt', u'gte', u'contains', u'lt', u'iendswith', u'icontains', u'iexact', u'isnull', u'range', u'istartswith', u'lte', u'in', u'endswith', u'exact'])¶
-
url_filter.filtersets package¶
-
class
url_filter.filtersets.base.
FilterSet
(source=None, *args, **kwargs)[source]¶ Bases:
url_filter.filters.Filter
Main user-facing classes to use filtersets.
FilterSet
primarily does:- takes queryset to filter
- takes querystring data which will be used to filter given queryset
- from the querystring, it constructs a list of
LookupConfig
- loops over the created configs and attemps to get
FilterSpec
for each - in the process, if delegates the job of constructing spec to child filters when any match is found between filter defined on the filter and name in the config
Parameters: - source (str) – Name of the attribute for which which filter applies to
within the model of the queryset to be filtered
as given to the
FilterSet
. - data (QueryDict, optional) – QueryDict of querystring data.
Only optional when
FilterSet
is used a nested filter within anotherFilterSet
. - queryset (iterable, optional) – Can be any iterable as supported by the filter backend.
Only optional when
FilterSet
is used a nested filter within anotherFilterSet
. - context (dict, optional) – Context for filtering. This is passed to filtering backend.
Usually this would consist of passing
request
andview
object from the Django view. - strict_mode (str, optional) – Strict mode how
FilterSet
should behave when any validation fails. SeeStrictMode
doc for more information. Default isdrop
.
-
filter_backend_class
¶ Class to be used as filter backend. By default
DjangoFilterBackend
is used.
-
filter_options_class
¶ Class to be used to construct
Meta
duringFilterSet
class creation time in its metalclass.
-
default_filter
¶ Cached property for looking up default filter. Default filter is a filter which is defined with
is_default=True
. Useful when lookup config references nested filter without specifying which field to filter. In that case default filter will be used.
-
filter
()[source]¶ Main method which should be used on root
FilterSet
to filter queryset.This method:
- asserts that filtering is being done on root
FilterSet
and that all necessary data is provided - creates ``LookupConfig``s from the provided data (querystring)
- loops over all configs and attemps to get
FilterSpec
for all of them - instantiates filter backend
- uses the created filter specs to filter queryset by using specs
Returns: Filtered queryset Return type: querystring - asserts that filtering is being done on root
-
filter_backend
¶ Property for getting instantiated filter backend.
Primarily useful when accessing filter_backend outside of the filterset such as leaf filters or integration layers since backend has useful information for both of those examples.
-
filter_backend_class
alias of
DjangoFilterBackend
-
filter_options_class
alias of
FilterSetOptions
-
filters
¶ Cached property for accessing filters available in this filteset. In addition to getting filters via
get_filters
, this property binds all filters to the filtset by usingbind
.See also
get_filters
,bind
-
get_filter_backend
()[source]¶ Get instantiated filter backend class.
This backend is then used to actually filter queryset.
-
get_filters
()[source]¶ Get all filters defined in this filterset. By default only declared filters are returned however this methoc can be used a hook to customize that.
-
get_spec
(config)[source]¶ Get
FilterSpec
for the givenLookupConfig
.If the config is non leaf config (it has more nested fields), then the appropriate matching child filter is used to get the spec. If the config however is a leaf config, then
default_filter
is used to get the spec, when available, and if not, this filter is skipped.Parameters: config (LookupConfig) – Config for which to generate FilterSpec
Returns: Individual filter spec Return type: FilterSpec
-
get_specs
()[source]¶ Get
FilterSpecs
for the given querystring data.This function does:
- unpacks the querystring data to ``LookupConfig``s
- loops throught all configs and uses appropriate children filters to generate ``FilterSpec``s
- if any validations fails while generating specs,
all errors are collected and depending on
strict_mode
it reraises the errors or ignores them.
Returns: List of ``FilterSpec``s Return type: list
-
class
url_filter.filtersets.base.
FilterSetOptions
(options=None)[source]¶ Bases:
object
Base class for handling options passed to
FilterSet
viaMeta
attribute.
-
class
url_filter.filtersets.base.
StrictMode
[source]¶ Bases:
enum.Enum
Strictness mode enum.
Drop (default) (default): ignores all filter failures. when any occur, FilterSet
simply then does not filter provided queryset.Fail: when validation fails for any filter within FilterSet
, all error are compiled and cumulativeValidationError
is raised.-
drop
= <StrictMode.drop: u'drop'>¶
-
fail
= <StrictMode.fail: u'fail'>¶
-
-
class
url_filter.filtersets.django.
ModelFilterSet
(source=None, *args, **kwargs)[source]¶ Bases:
url_filter.filtersets.base.FilterSet
FilterSet
for Django models.The filterset can be configured via
Meta
class attribute, very much like Django’sModelForm
is configured.-
Meta
= <url_filter.filtersets.django.ModelFilterSetOptions object>¶
Build a
FilterSet
for a Django relation model field such asForeignKey
.
-
build_filterset_from_reverse_field
(field)[source]¶ Build a
FilterSet
for a Django reverse relation model field.
-
filter_options_class
¶ alias of
ModelFilterSetOptions
-
get_filters
()[source]¶ Get all filters defined in this filterset including filters corresponding to Django model fields.
-
get_form_field_for_field
(field)[source]¶ Get form field for the given Django model field.
By default
Field.formfield()
is used to get the form field unless an overwrite is present for the field. Overwrites are useful for non-standard fields likeFileField
since in that caseCharField
should be used.
-
-
class
url_filter.filtersets.django.
ModelFilterSetOptions
(options=None)[source]¶ Bases:
object
Custom options for ``FilterSet``s used for Django models.
-
model
¶ Model
Django model class from which
FilterSet
will extract necessary filters.
-
fields
¶ None, list, optional
Specific model fields for which filters should be created for. By default it is
None
in which case for all fields filters will be created for.
-
exclude
¶ list, optional
Specific model fields for which filters should not be created for.
bool, optional
bool, optional
-
-
class
url_filter.filtersets.sqlalchemy.
SQLAlchemyModelFilterSet
(source=None, *args, **kwargs)[source]¶ Bases:
url_filter.filtersets.base.FilterSet
FilterSet
for SQLAlchemy models.The filterset can be configured via
Meta
class attribute, very much like Django’sModelForm
is configured.-
Meta
= <url_filter.filtersets.django.ModelFilterSetOptions object>¶
-
filter_options_class
¶ alias of
ModelFilterSetOptions
-
Submodules¶
url_filter.exceptions module¶
-
exception
url_filter.exceptions.
SkipFilter
[source]¶ Bases:
exceptions.Exception
Exception to be used when any particular filter within the
FilterSet
should be skipped.Possible reasons for skipping the field:
- filter lookup config is invalid (e.g. using wrong field name - field is not present in filter set)
- filter lookup value is invalid (e.g. submitted “a” for integer field)
url_filter.fields module¶
-
class
url_filter.fields.
MultipleValuesField
(child=None, min_values=2, max_values=None, many_validators=None, delimiter=u', ', *args, **kwargs)[source]¶ Bases:
django.forms.fields.CharField
Custom Django field for validating/cleaning multiple values given in a single value separated by a delimiter.
Parameters: - child (Field, optional) – Another Django form field which should be used.
- min_values (int, optional) – Minimum number of values which must be provided. By default at least 2 values are required.
- max_values (int, optional) – Maximum number of values which can be provided. By default no maximum is enforced.
- max_validators (list, optional) – Additional validators which should be used to validate all values once wplit by the delimiter.
- delimiter (str, optional) – The delimiter by which the value will be split into
multiple values.
By default
,
is used.
-
clean
(value)[source]¶ Custom
clean
which first validates the value first by using standardCharField
and if all passes, it applies similar validations for each value once its split.
-
many_run_validators
(values)[source]¶ Run each validation from
many_validators
for the cleaned values.
url_filter.filters module¶
-
class
url_filter.filters.
Filter
(source=None, *args, **kwargs)[source]¶ Bases:
object
Filter class which main job is to convert leaf
LookupConfig
toFilterSpec
.Each filter by itself is meant to be used a “field” in the
FilterSpec
.Parameters: - source (str) – Name of the attribute for which which filter applies to
within the model of the queryset to be filtered
as given to the
FilterSet
. - form_field (Field) – Instance of Django’s
forms.Field
which will be used to clean the filter value as provided in the queryset. For example if field isIntegerField
, this filter will make sure to convert the filtering value to integer before creating aFilterSpec
. - lookups (list, optional) – List of strings of allowed lookups for this filter. By default all supported lookups are allowed.
- default_lookup (str, optional) – If the lookup is not provided in the querystring lookup key,
this lookup will be used. By default
exact
lookup is used. For example the default lookup is used when querystring key isuser__profile__email
which is missing the lookup soexact
will be used. - is_default (bool, optional) – Boolean specifying if this filter should be used as a default
filter in the parent
FilterSet
. By default it isFalse
. Primarily this is used when querystring lookup key refers to a nestedFilterSet
however it does not specify which filter to use. For example lookup keyuser__profile
intends to filter something in the user’s profile however it does not specify by which field to filter on. In that case the default filter within profileFilterSet
will be used. At most, one default filter should be provided in theFilterSet
.
-
parent
¶ FilterSet
Parent
FilterSet
to which this filter is bound to
-
name
¶ str
Name of the field as it is defined in parent
FilterSet
-
bind
(name, parent)[source]¶ Bind the filter to the filterset.
This method should be used by the parent
FilterSet
since it allows to specify the parent and name of each filter within the filterset.
-
clean_value
(value, lookup)[source]¶ Clean the filter value as appropriate for the given lookup.
Parameters: - value (str) – Filter value as given in the querystring to be validated and cleaned by using appropriate Django form field
- lookup (str) – Name of the lookup
See also
-
components
¶ List of all components (source names) of all parent filtersets.
-
get_form_field
(lookup)[source]¶ Get the form field for a particular lookup.
This method does not blindly return
form_field
attribute since some lookups require to use different validations. For example for if theform_field
isCharField
but the lookup isisnull
, it makes more sense to useBooleanField
as form field.Parameters: lookup (str) – Name of the lookup Returns: Instantiated form field appropriate for the given lookup. Return type: Field
-
get_spec
(config)[source]¶ Get the
FilterSpec
for the providedconfig
.Parameters: config (LookupConfig) – Lookup configuration for which to build FilterSpec
. The lookup should be a leaf configuration otherwiseValidationError
is raised.Returns: spec constructed from the given configuration. Return type: FilterSpec
-
lookups
¶
-
root
¶ This gets the root filterset.
-
source
¶ Source field/attribute in queryset model to be used for filtering.
This property is helpful when
source
parameter is not provided when instantiatingFilter
since it will use the filter name as it is defined in theFilterSet
. For example:>>> class MyFilterSet(FilterSet): ... foo = Filter(form_field=CharField()) ... bar = Filter(source='stuff', form_field=CharField()) >>> fs = MyFilterSet() >>> print(fs.fields['foo'].source) foo >>> print(fs.fields['bar'].source) stuff
- source (str) – Name of the attribute for which which filter applies to
within the model of the queryset to be filtered
as given to the
url_filter.utils module¶
-
class
url_filter.utils.
FilterSpec
(components, lookup, value, is_negated=False)[source]¶ Bases:
object
Class for describing filter specification.
The main job of the
FilterSet
is to parse the submitted lookups into a list of filter specs. A list of these specs is then used by the filter backend to actually filter given queryset.The reason why filtering is decoupled from the
FilterSet
is because this allows to implement filter backends not related to Django.-
components
¶ list
A list of strings which are names of the keys/attributes to be used in filtering of the queryset. For example lookup config with key
user__profile__email
will be components of ``[‘user’, ‘profile’, ‘email’].
-
lookup
¶ str
Name of the lookup how final key/attribute from
components
should be compared. For example lookup config with keyuser__profile__email__contains
will have a lookupcontains
.
-
value
¶ Value of the filter.
-
is_negated
¶ bool, optional
Whether this filter should be negated. By default its
False
.
-
-
class
url_filter.utils.
LookupConfig
(key, data)[source]¶ Bases:
object
Lookup configuration which is used by
FilterSet
to create aFilterSpec
.The main purpose of this config is to allow the use if recursion in
FilterSet
. Each lookup key (the keys in the querystring) is parsed into a nested one-key dictionary which lookup config stores.For example the querystring:
?user__profile__email__endswith=gmail.com
is parsed into the following config:
{ 'user': { 'profile': { 'email': { 'endswith': 'gmail.com' } } } }
-
key
¶ str
Full lookup key from the querystring. For example
user__profile__email__endswith
-
data
¶ dict, str
Either:
- nested dictionary where the key is the next key within
the lookup chain and value is another
LookupConfig
- the filtering value as provided in the querystring value
- nested dictionary where the key is the next key within
the lookup chain and value is another
Parameters: - key (str) – Full lookup key from the querystring.
- data (dict, str) – A regular vanilla Python dictionary. This class automatically converts nested dictionaries to instances of LookupConfig. Alternatively a filtering value as provided in the querystring.
-
name
¶ If the
data
is nestedLookupConfig
, this gets its first lookup key.
-
value
¶ If the
data
is nestedLookupConfig
, this gets its first lookup value which could either be anotherLookupConfig
or actual filtering value.
-
-
class
url_filter.utils.
SubClassDict
[source]¶ Bases:
dict
Special-purpose
dict
with special getter for looking up values by finding matching subclasses.This is better illustrated in an example:
>>> class Klass(object): pass >>> class Foo(object): pass >>> class Bar(Foo): pass >>> mapping = SubClassDict({ ... Foo: 'foo', ... Klass: 'klass', ... }) >>> print(mapping.get(Klass)) klass >>> print(mapping.get(Foo)) foo >>> print(mapping.get(Bar)) foo
url_filter.validators module¶
-
class
url_filter.validators.
MaxLengthValidator
(limit_value, message=None)[source]¶ Bases:
django.core.validators.MaxLengthValidator
Customer Django max length validator with better-suited error message
-
clean
(x)¶
-
code
= u'max_length'¶
-
compare
(a, b)¶
-
deconstruct
(obj)¶ Returns a 3-tuple of class import path, positional arguments, and keyword arguments.
-
message
= <django.utils.functional.__proxy__ object>¶
-
-
class
url_filter.validators.
MinLengthValidator
(limit_value, message=None)[source]¶ Bases:
django.core.validators.MinLengthValidator
Customer Django min length validator with better-suited error message
-
clean
(x)¶
-
code
= u'min_length'¶
-
compare
(a, b)¶
-
deconstruct
(obj)¶ Returns a 3-tuple of class import path, positional arguments, and keyword arguments.
-
message
= <django.utils.functional.__proxy__ object>¶
-
Django URL Filter¶
Django URL Filter provides a safe way to filter data via human-friendly URLs.
- Free software: MIT license
- GitHub: https://github.com/miki725/django-url-filter
- Documentation: http://django-url-filter.readthedocs.org/
Overview¶
The main goal of Django URL Filter is to provide an easy URL interface for filtering data. It allows the user to safely filter by model attributes and also allows to specify the lookup type for each filter (very much like Django’s filtering system in ORM).
For example the following will retrieve all items where the id is
5
and title contains "foo"
:
example.com/listview/?id=5&title__contains=foo
In addition to basic lookup types, Django URL Filter allows to
use more sophisticated lookups such as in
or year
.
For example:
example.com/listview/?id__in=1,2,3&created__year=2013
Requirements¶
- Python 2.7, 3.x, pypy or pypy3
- Django 1.8+ (there are plans to support older Django versions)
- Django REST Framework 2 or 3 (only if you want to use DRF integration)
Usage Example¶
To make example short, it demonstrates Django URL Filter integration with Django REST Framework but it can be used without DRF (see below).
class UserViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [DjangoFilterBackend]
filter_fields = ['username', 'email']
Alternatively filteset can be manually created and used directly to filter querysets:
class UserFilterSet(ModelFilterSet):
class Meta(object):
model = User
query = QueryDict('email__contains=gmail&joined__gt=2015-01-01')
fs = UserFilterSet(data=query, queryset=User.objects.all())
filtered_users = fs.filter()
Above will automatically allow the use of all of the Django URL Filter features. Some possibilities:
# get user with id 5
example.com/users/?id=5
# get user with id either 5, 10 or 15
example.com/users/?id__in=5,10,15
# get user with id between 5 and 10
example.com/users/?id__range=5,10
# get user with username "foo"
example.com/users/?username=foo
# get user with username containing case insensitive "foo"
example.com/users/?username__icontains=foo
# get user where username does NOT contain "foo"
example.com/users/?username__icontains!=foo
# get user who joined in 2015 as per user profile
example.com/users/?profile__joined__year=2015
# get user who joined in between 2010 and 2015 as per user profile
example.com/users/?profile__joined__range=2010-01-01,2015-12-31
# get user who joined in after 2010 as per user profile
example.com/users/?profile__joined__gt=2010-01-01
Features¶
Human-friendly URLs
Filter querystring format looks very similar to syntax for filtering in Django ORM. Even negated filters are supported! Some examples:
example.com/users/?email__contains=gmail&joined__gt=2015-01-01 example.com/users/?email__contains!=gmail # note !
Related models
Support related fields so that filtering can be applied to related models. For example:
example.com/users/?profile__nickname=foo
Decoupled filtering
How URLs are parsed and how data is filtered is decoupled. This allows the actual filtering logic to be decoupled from Django hence filtering is possible not only with Django ORM QuerySet but any set of data can be filtered (e.g. SQLAlchemy query objects) assuming corresponding filtering backend is implemented.
Usage-agnostic
This library decouples filtering from any particular usage-pattern. It implements all the basic building blocks for creating filtersets but it does not assume how they will be used. To make the library easy to use, it ships with some integrations with common usage patterns like integration with Django REST Framework. This means that its easy to use in custom applications with custom requirements (which is probably most of the time!)