Filtering and ordering with Restless

Posted on 29 December 2014

Let's continue with my previous blog post on Restless introduction with Django. Today I'll show you two quick and simple Mixins for Restless. One for filtering and another for ordering.

I won't show you how to create Django app, models, etc. This is not the subject.

Just to be clear, I have this for our Pizza shop.

from django.db import models

class Pizza(models.Model):
    name = models.CharField(max_length=100)
    price = models.FloatField()
    is_vegetarian = models.BooleanField(default=False)

class Ingredient(models.Model):
    name = models.CharField(max_length=100)

class PizzaIngredient(models.Model):
    pizza = models.ForeignKey('Pizza', related_name='ingredients')
    ingredient = models.ForeignKey('Ingredient')

And my

from import DjangoResource
from restless.preparers import FieldsPreparer

from .models import Pizza

class PizzaResource(DjangoResource):
    preparer = FieldsPreparer(fields={
        'id': 'id', 'name': 'name'})

    def list(self):
        return Pizza.objects.all()


We are building a very simple and not complete APIFilterMixin class.

1class APIFilterMixin:
2    allowed_fields_filter = []
4    def filter(self, queryset):
5        filters = {}
6        for arg in self.request.GET:
7            if arg in self.allowed_fields_filter:
8                filters.update({arg: self.request.GET.get(arg)})
9        return queryset.filter(**filters)

As you can see allowed_fields_filter allow us to put filters (with lookup) that we want to authorize on our Resource.

This mixin only expose a single filter method which take one argument, a QuerySet instance.

At line 6 we just iterate over all request arguments, check if this argument is in allowed_fields_filter, update filters dictionary and at (line 9), we unpack filters in a filter method.

And this is updated revision of our previous with new mixin:

class PizzaResource(APIFilterMixin, DjangoResource):
    preparer = FieldsPreparer(fields={
        'id': 'id', 'name': 'name'})
    allowed_fields_filter = [
        'name', 'name__startswith',
        'price', 'price__lte', 'price__gte',

    def list(self):
        qs = Pizza.objects.all()
        return self.filter(qs)

We can now give all filters we have allowed in allowed_fields_filter, including relation lookups.


Ordering is even more simple than filtering. Look how restless allow us to cleanly create our minimal API.

 1class APIOrderingMixin:
 2    allowed_fields_ordering = []
 3    ordering_field = 'order_by'
 5    def ordering(self, queryset):
 6        order_by = self.request.GET.get(self.ordering_field)
 7        if not order_by:
 8            return queryset
10        if order_by.split('-')[-1] in self.allowed_fields_ordering:
11            return queryset.order_by(order_by)
13        return queryset

This mixin support custom ordering field name with ordering_field. We can allow fields we want with allowed_fields_ordering. Another simple but cool feature is reverse ordering support (line 10).

Just add APIOrderingMixin to your PizzaResource and here we go.

Happy programming everybody!