Skip to main content

A Declarative library for Django REST Framework

Project description

drf-restflow

A declarative library for Django REST Framework. Write type-safe REST APIs with Python annotations, automatic validation, and minimal boilerplate.

Overview

drf-restflow works alongside DRF, not as a replacement. It leverages DRF's powerful serializer infrastructure and extends it with declarative patterns for common tasks.

Heavily inspired by FastAPI and django-filter, bringing modern Python features and intuitive API design to Django REST Framework.

Full documentation is live at: Restflow Documentation

Current Release: (Alpha)

Available Features:

Table of Contents

Motivation

Hi, I’m Khan, the author of drf-restflow.

This library was born from the realities of building APIs in a fast-moving startup environment. Most of my work involved large database tables, constantly evolving product requirements, and the challenge of exposing clean, reliable REST APIs. While, also ensuring that new developers could onboard quickly and understand the codebase and business logic as early as possible.

I started with django-filter, which is an excellent and very mature tool. But as our product grew (and pivoted repeatedly), the FilterSets became harder to maintain. They were getting long, repetitive, and full of boilerplate.

Some might say this was a skill issue, and honestly, I agree.

But the truth is, I’m a lazy developer.

I like writing less code. I like being fast. I like tools that let me declare what I want instead of wiring everything by hand. Over time, I built small internal utilities to reduce repetition and make filtering easier. Those tools worked well for my case, , So I decided to compile all those internal utilities into a proper library, so I can use it for other projects as well.

Many of the internal toolsets created were built from scratch, which brought some inconsistency, instead of reinventing the wheel, I later decided to use what is already available and battle tested and borrowed ideas from different libraries, for example FastAPI, django-filter, and django-ninja. That's how I started drf-restflow, a library that doesn't replace Django Rest Framework but uses its powerful features. One sidenote, there might be other libraries that do exactly what drf-restflow promises to do, or maybe do more than that, I might be unaware, So, Feel free to contribute or provide any insights, and constructive criticism, thank you.

Installation

pip install drf-restflow

or using uv

uv add drf-restflow

Requirements

  • Python 3.10+
  • Django 3.2+
  • Django REST Framework 3.14+
  • PostgreSQL (optional, for PostgreSQL-specific features)

Key Features

Filtering

The current release focuses on declarative filtering with these capabilities:

Declarative Field Definitions

Define filters using type annotations, explicit field declarations, or automatic model generation:

from restflow.filters import FilterSet

class ProductFilterSet(FilterSet):
    name: str                                    # Type annotation
    price = IntegerField(lookups=["comparison"]) # Explicit field

    class Meta:
        model = Product                          # Model-based generation

Automatic Lookup Generation

Generate multiple filter variants from a single field definition:

class ProductFilterSet(FilterSet):
    price = IntegerField(lookups=["comparison"])

# Automatically generates:
# - price (exact match)
# - price__gt, price__gte, price__lt, price__lte (comparisons)
# - price!, price__gt!, price__gte!, ... (negations)

Type-Safe Validation

Built on DRF's validation system with automatic type conversion and detailed error messages:

# GET /api/products?price__gte=invalid
# Returns: {"price__gte": ["A valid integer is required."]}

# GET /api/products?price=-10
# Returns: {"price": ["Ensure this value is greater than or equal to 0."]}

Universal Negation Support

Exclude values using the ! suffix on any filter:

# Exclude categories
GET /api/products?category!=electronics&category!=books

# Exclude price range
GET /api/products?price__gte!=1000  # NOT >= 1000 (i.e., < 1000)

# Exclude keywords
GET /api/products?name__icontains!=refurbished

Custom Filter Methods

Implement complex filtering logic with custom methods using Q objects:

from django.db.models import Q

class ProductFilterSet(FilterSet):
    in_stock = BooleanField(method="filter_in_stock")
    search = StringField(method="filter_search")

    def filter_in_stock(self, filterset, queryset, value):
        if value:
            return Q(inventory__gt=0)
        return Q(inventory=0)

    def filter_search(self, filterset, queryset, value):
        return Q(name__icontains=value) | Q(description__icontains=value)

PostgreSQL Features

First-class support for PostgreSQL-specific functionality:

from django.contrib.postgres.search import SearchVector, SearchQuery

class ProductFilterSet(FilterSet):
    # Array fields
    tags = ListField(child=StringField(), lookups=["pg_array"])
    # Generates: tags__contains, tags__overlap, tags__contained_by

    # Full-text search
    search = StringField(method="filter_fulltext")

    def filter_fulltext(self, filterset, queryset, value):
        vector = SearchVector('name', 'description')
        query = SearchQuery(value)
        return queryset.filter(search_vector=query)

Operators & Processors

Control filter combination logic and queryset transformations:

class ProductFilterSet(FilterSet):
    name: str
    category: str

    class Meta:
        operator = "OR"  # Combine filters with OR instead of AND

        preprocessors = [      # Run before filtering
            exclude_deleted,
            apply_permissions,
            optimize_queries,
        ]

        postprocessors = [     # Run after filtering
            apply_default_ordering,
            ensure_distinct,
        ]

Quick Example

from django.db import models
from restflow.filters import FilterSet, StringField, IntegerField
from rest_framework.decorators import api_view
from rest_framework.response import Response

# Model
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.IntegerField()
    category = models.CharField(max_length=50)
    in_stock = models.BooleanField(default=True)

# FilterSet
class ProductFilterSet(FilterSet):
    name = StringField(lookups=["icontains"])
    price = IntegerField(lookups=["comparison"])
    category: str

    class Meta:
        model = Product
        order_fields = [("price", "price"), ("name", "name")]

# View
@api_view(['GET'])
def product_list(request):
    queryset = Product.objects.all()
    filterset = ProductFilterSet(request=request)
    filtered_qs = filterset.filter_queryset(queryset)
    return Response({
        'count': filtered_qs.count(),
        'results': list(filtered_qs.values())
    })

API Usage:

# Filter by name containing "laptop"
GET /api/products?name__icontains=laptop

# Filter by price range
GET /api/products?price__gte=100&price__lte=500

# Exclude categories
GET /api/products?category!=electronics

# Order by price descending
GET /api/products?order_by=-price

# Combine filters
GET /api/products?name__icontains=laptop&price__lte=1000&category!=refurbished&order_by=price

Roadmap

Current Release: Alpha

Filtering : Declarative query parameter filtering with type annotations

Future

  • Serializer enhancements: Declarative serializers with type annotations
  • API / View: FastAPI style api / view declaration
  • Async Support: Async filters and views

Alpha Notice: This is the first alpha release. The filtering API is mostly stable, but breaking changes may occur as we add features and gather community feedback.

Contributing

Contributions are welcome! Check out the Contributing Guide for guidelines.

License

BSD 3-Clause License LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

drf_restflow-1.0.0a1.tar.gz (36.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

drf_restflow-1.0.0a1-py3-none-any.whl (21.3 kB view details)

Uploaded Python 3

File details

Details for the file drf_restflow-1.0.0a1.tar.gz.

File metadata

  • Download URL: drf_restflow-1.0.0a1.tar.gz
  • Upload date:
  • Size: 36.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for drf_restflow-1.0.0a1.tar.gz
Algorithm Hash digest
SHA256 e2defabfe36776613e221acbab69e7a1cf2af56b1e0bbf7af2b75ebe68a9b0a5
MD5 e89db04ca89b7d69271a43c267a4819f
BLAKE2b-256 4d5b5e4203905e23f68ab0769f0d8b122fa56a5751f5c96fe6ae86a110a2312d

See more details on using hashes here.

File details

Details for the file drf_restflow-1.0.0a1-py3-none-any.whl.

File metadata

  • Download URL: drf_restflow-1.0.0a1-py3-none-any.whl
  • Upload date:
  • Size: 21.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for drf_restflow-1.0.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 14648108f5cd938d5ed153793b28d68a4fcd2c6f988cddd9289c3d9bf91d870a
MD5 961be99135ef0882aba1a8f56ef73196
BLAKE2b-256 6dbc02c9e5a6cce93aa40834d0d0b84e64a8510df5dc82173c5ce0d1909914b5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page