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 a Filter within another FilterSet hence allowing filtering by related models.
  • form_field is used to validate the filter value. Each lookup however can overwrite validation. For example year lookup will use IntegerField rather then DateField.
  • Filter can restrict allowed lookups for that field by using lookup 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 case FilterSet 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 otherwise DjangoFilterBackend 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:

  1. Parse the URL querystring into LookupConfig
  2. Loop throught all the configs and generate FilterSpec when possible
  3. 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:

  1. FilterSet is instantiated with querystring data as well as querystring to filter.
  2. FilterSet is asked to filter given data via filter method which kicks in all the steps below.
  3. FilterSet finds all filters it is capable of Filtering via get_filters. This is where custom filtersets can hook into to do custom stuff like extracting filters from a Django model.
  4. FilterSet binds all child filters to itself via bind. This practically sets parent and name.
  5. Root FilterSet loops through all querystring pairs and generates LookupConfig for all of them.
  6. 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 the LookupConfig dict. If that key is found in available filters, that filer is used and otherwise that config is skipped. This is among the reasons why LookupConfig is used since it allows this step to be very simple.
  7. 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.
  8. 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 in default_lookup parameter when instantiating Filter. 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 with rainbows since it is not a valid lookup value).
  9. Now that Filter validated the lookup itself, it cleans the actual filter value by using either form_field as passed as parameter when instantiating Filter or by using loopup overwrite. Overwrites are necessary for more exotic lookups like in or year since they need to validate data in a different way.
  10. 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.
  11. At this point, root FilterSpec will get the FilterSpec as bubbled up from the leaf filter. If any ValidationError exceptions are raised, then depending on strict_mode, it will either ignores errors or will propagate them up to the caller of the filterset.
  12. Once all specs are collected from all the querystring key-value-pairs, root FilterSet instantiates a filter backend and passes it all the specs.
  13. 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 generating FilterSpec 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
Submodules
url_filter.backends.base module
class url_filter.backends.base.BaseFilterBackend(queryset, context=None)[source]

Bases: object

bind(specs)[source]
filter()[source]

Main method for filtering queryset.

Note

MUST be implemented by subclasses

get_model()[source]

Get the queryset model.

Note

MUST be implemented by subclasses

model
supported_lookups = set([])
url_filter.backends.django module
class url_filter.backends.django.DjangoFilterBackend(queryset, context=None)[source]

Bases: url_filter.backends.base.BaseFilterBackend

excludes
filter()[source]
get_model()[source]
includes
prepare_spec(spec)[source]
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'])
url_filter.backends.sqlalchemy module
class url_filter.backends.sqlalchemy.SQLAlchemyFilterBackend(*args, **kwargs)[source]

Bases: url_filter.backends.base.BaseFilterBackend

build_clause(spec)[source]
filter()[source]
get_model()[source]
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.backends.sqlalchemy.lower(value)[source]
url_filter.filtersets package
Submodules
url_filter.filtersets.base module
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 another FilterSet.
  • queryset (iterable, optional) – Can be any iterable as supported by the filter backend. Only optional when FilterSet is used a nested filter within another FilterSet.
  • context (dict, optional) – Context for filtering. This is passed to filtering backend. Usually this would consist of passing request and view object from the Django view.
  • strict_mode (str, optional) – Strict mode how FilterSet should behave when any validation fails. See StrictMode doc for more information. Default is drop.
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 during FilterSet 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
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 using bind.

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 given LookupConfig.

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
repr(prefix=u'')[source]
validate_key(key)[source]

Validate that LookupConfig key is correct.

This is the key as provided in the querystring. Currently key is validated against a regex expression.

class url_filter.filtersets.base.FilterSetOptions(options=None)[source]

Bases: object

Base class for handling options passed to FilterSet via Meta 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 cumulative ValidationError is raised.
drop = <StrictMode.drop: u'drop'>
fail = <StrictMode.fail: u'fail'>
url_filter.filtersets.django module
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’s ModelForm is configured.

Meta = <url_filter.filtersets.django.ModelFilterSetOptions object>
build_filter_from_field(field)[source]

Build Filter for a standard Django model field.

Build a FilterSet for a Django relation model field such as ForeignKey.

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 like FileField since in that case CharField should be used.

get_model_field_names()[source]

Get a list of all model fields.

This is used when Meta.fields is None in which case this method returns all model fields.

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

url_filter.filtersets.sqlalchemy module
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’s ModelForm is configured.

Meta = <url_filter.filtersets.django.ModelFilterSetOptions object>
build_filter_from_field(field)[source]

Build Filter for a standard SQLAlchemy 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 SQLAlchemy model field.

get_model_field_names()[source]

Get a list of all model fields.

This is used when Meta.fields is None in which case this method returns all model fields.

url_filter.integrations package
Submodules
url_filter.integrations.drf module
class url_filter.integrations.drf.DjangoFilterBackend[source]

Bases: rest_framework.filters.BaseFilterBackend

default_filter_set

alias of ModelFilterSet

filter_queryset(request, queryset, view)[source]
get_filter_class(view, queryset=None)[source]
get_filter_context(request, view)[source]
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 standard CharField 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.

many_to_python(value)[source]

Method responsible to split the value into multiple values by using the delimiter and cleaning each one as per the child field.

many_validate(values)[source]

Hook for validating all 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 to FilterSpec.

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 is IntegerField, this filter will make sure to convert the filtering value to integer before creating a FilterSpec.
  • 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 is user__profile__email which is missing the lookup so exact 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 is False. Primarily this is used when querystring lookup key refers to a nested FilterSet however it does not specify which filter to use. For example lookup key user__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 profile FilterSet will be used. At most, one default filter should be provided in the FilterSet.
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

get_form_field()

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 the form_field is CharField but the lookup is isnull, it makes more sense to use BooleanField 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 provided config.

Parameters:config (LookupConfig) – Lookup configuration for which to build FilterSpec. The lookup should be a leaf configuration otherwise ValidationError is raised.
Returns:spec constructed from the given configuration.
Return type:FilterSpec
lookups
repr(prefix=u'')[source]
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 instantiating Filter since it will use the filter name as it is defined in the FilterSet. 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
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 key user__profile__email__contains will have a lookup contains.

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 a FilterSpec.

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
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.
as_dict()[source]

Converts the nested LookupConfig``s to a regular ``dict.

is_key_value()[source]
name

If the data is nested LookupConfig, this gets its first lookup key.

value

If the data is nested LookupConfig, this gets its first lookup value which could either be another LookupConfig 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
get(k, d=None)[source]

If no value is found by using Python’s default implementation, try to find the value where the key is a base class of the provided search class.

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

https://travis-ci.org/miki725/django-url-filter.svg?branch=master https://coveralls.io/repos/miki725/django-url-filter/badge.svg?branch=master&service=github

Django URL Filter provides a safe way to filter data via human-friendly URLs.

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)

Installing

Easiest way to install this library is by using pip:

$ pip install django-url-filter

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!)

Indices and tables