🔍 Filtering
Django Headless ships LookupFilter, a permissive filter backend that maps query string parameters directly to Django ORM lookups. It is enabled on the generated routes by default (HEADLESS.DEFAULT_FILTER_BACKENDS). To use it on the rest of your API as well, configure DRF:
REST_FRAMEWORK = {
"DEFAULT_FILTER_BACKENDS": [
"headless.rest.filters.LookupFilter",
],
}
Syntax
Any supported lookup for a field can be used as a query parameter, using the ORM's field__lookup naming:
# Basic filtering
GET /api/blog.blogpost?published=true
# Field lookups
GET /api/blog.blogpost?title__icontains=django
GET /api/blog.blogpost?created_at__gte=2023-01-01
GET /api/blog.blogpost?views__range=10,100
# Multiple filters combine with AND
GET /api/blog.blogpost?published=true&created_at__year=2023
Exclusions
Prefix a parameter with ~ (configurable, see settings) to exclude matches:
# Everything except unpublished posts
GET /api/blog.blogpost?~published=false
Multi-value lookups
Multi-value lookups (in, range) accept comma-separated values:
GET /api/blog.blogpost?id__in=1,2,3
Repeated parameters work as well: ?id__in=1&id__in=2.
Type casting
Values are cast to the field's type: booleans as true/1/on and false/0/off, integers, decimals and floats parsed accordingly, and isnull accepts a boolean. Boolean and null matching is case-insensitive; text values keep their original casing, so case-sensitive lookups like exact behave as expected.
Invalid parameters — unknown fields, unsupported lookups, bad values — answer 400 Bad Request with the reason in the error detail:
{
"detail": "Field 'nonexistent' does not exist"
}