Usage

Vanilla

In its simplest form, Django URL Filter usage revolves around FilterSet. They can be used manually:

from django import forms
from url_filter.filters 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 lookups 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. Additionally SQLAlchemyModelFilterSet is available to be able to easily create filter sets from SQLAlchemy models. 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 ModelFilterSet 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.

Plain Filtering

In addition to supporting regular ORMs django-url-filter also allows to filter plain Python lists of either objects or dictionaries. This feature is primarily meant to filter data-sources without direct filtering support such as lists of data in redis. For example:

from django import forms
from url_filter.backend.plain import PlainFilterBackend
from url_filter.filtersets.plain import PlainModelFilterSet

class UserFilterSet(PlainModelFilterSet):
    filter_backend_class = PlainFilterBackend

    class Meta(object):
        # the filterset will generate fields from the
        # primitive Python data-types
        model = {
            'username': 'foo',
            'password': bar,
            'joined': date(2015, 1, 2),
            'profile': {
                'preferred_name': 'rainbow',
            }
        }

fs = UserFilterSet(data=QueryDict(), queryset=[{...}, {...}, ...])
fs.filter()

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 Class Based Views

FilterSet or related classes can directly be used within Django class-based-views:

class MyFilterSet(ModelFilterSet):
    class Meta(object):
        model = MyModel

class MyListView(ListView):
    queryset = MyModel.objects.all()
    def get_queryset(self):
        qs = super(MyListView, self).get_queryset()
        return MyFilterSet(data=self.request.GET, queryset=qs).filter()

Django REST Framework

Django URL Filter can rather easily be integrated with DRF. For that, a DRF-specific filter backend DjangoFilterBackend 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

For more available options, please refer to DjangoFilterBackend documentation.