Skip to main content

Easy CRUD operations for Django REST Framework.

Project description

DRF Easy CRUD

Enterprise-grade utility library for simplifying CRUD operations in Django REST Framework. Provides powerful filtering, pagination, and standardized CRUD methods to accelerate API development.


Installation

uv add drf-easy-crud

Features

  • 🔧 Simplified CRUD Operations: Static utility methods for GET, POST, PUT, PATCH, and DELETE operations
  • 🔍 Advanced Filtering: Wildcard pattern matching for text fields, comparison operators for numeric fields
  • 📄 Built-in Pagination: Standard pagination with configurable page sizes
  • 🔗 ForeignKey Support: Filter across related models using Django's double-underscore lookup syntax
  • 🛡️ Enterprise-Grade Error Handling: Comprehensive error handling with detailed logging
  • 📊 Type-Safe: Full type hints for better IDE support and code reliability
  • ⚡ Performance Optimized: Efficient queryset handling with optional hooks for customization

Quick Start

Basic Usage

from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response

from drf_easy_crud import CRUDUtils
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer


class MyModelViewSet(viewsets.ViewSet):
    """Example ViewSet using CRUDUtils."""

    def list(self, request: Request) -> Response:
        """List all instances with filtering and pagination."""
        return CRUDUtils.get(
            request=request,
            model_class=MyModel,
            serializer_class=MyModelSerializer,
        )

    def retrieve(self, request: Request, pk: int) -> Response:
        """Retrieve a single instance."""
        return CRUDUtils.get(
            request=request,
            model_class=MyModel,
            serializer_class=MyModelSerializer,
            pk=pk,
        )

    def create(self, request: Request) -> Response:
        """Create a new instance."""
        return CRUDUtils.post(
            request=request,
            serializer_class=MyModelSerializer,
        )

    def update(self, request: Request, pk: int) -> Response:
        """Full update of an instance."""
        return CRUDUtils.put(
            request=request,
            model_class=MyModel,
            serializer_class=MyModelSerializer,
            pk=pk,
        )

    def partial_update(self, request: Request, pk: int) -> Response:
        """Partial update of an instance."""
        return CRUDUtils.patch(
            request=request,
            model_class=MyModel,
            serializer_class=MyModelSerializer,
            pk=pk,
        )

    def destroy(self, request: Request, pk: int) -> Response:
        """Delete an instance."""
        return CRUDUtils.delete(
            model_class=MyModel,
            pk=pk,
        )

Advanced Features

Custom Queryset Hooks

Filter the base queryset before applying request filters:

def list(self, request: Request) -> Response:
    """List only active instances."""
    return CRUDUtils.get(
        request=request,
        model_class=MyModel,
        serializer_class=MyModelSerializer,
        queryset_hook=lambda: MyModel.objects.filter(is_active=True),
    )

Custom Pagination

Use your own pagination class:

from drf_easy_crud import CRUDUtils, StandardResultsSetPagination
from rest_framework.pagination import PageNumberPagination


class CustomPagination(PageNumberPagination):
    page_size = 50
    max_page_size = 200


def list(self, request: Request) -> Response:
    return CRUDUtils.get(
        request=request,
        model_class=MyModel,
        serializer_class=MyModelSerializer,
        pagination_class=CustomPagination,
    )

Custom Ordering

Specify default ordering for list endpoints:

def list(self, request: Request) -> Response:
    return CRUDUtils.get(
        request=request,
        model_class=MyModel,
        serializer_class=MyModelSerializer,
        ordering_field="-created_at",  # Newest first
    )

Filtering

The library provides powerful filtering capabilities through FilterUtils:

Text Field Wildcard Patterns

Pattern Description Example Matches
field=value* Starts with ?name=test* "test", "test123", "testing"
field=*value Ends with ?name=*test "mytest", "123test"
field=*value* Contains ?name=*test* "test", "mytest", "testing"
field=va*ue Middle wildcard ?name=t*t "test", "tart", "t123t"
field=value Exact match ?name=test "test" (case-insensitive)

Number Field Comparison Operators

Pattern Description Example Matches
field=value Exact match ?age=25 Exactly 25
field=>=value Greater than or equal ?age=>=25 25, 26, 27, ...
field=<=value Less than or equal ?age=<=100 ..., 98, 99, 100
field=>value Greater than ?age=>25 26, 27, 28, ...
field=<value Less than ?age=<25 ..., 23, 24

ForeignKey Lookups

Filter by related model fields using double underscores:

# Filter by related model's text field
GET /api/products/?category__name=electronics*

# Filter by related model's number field
GET /api/products/?category__priority=>=5

# Nested ForeignKey lookup
GET /api/orders/?customer__company__name=acme*

Filtering Examples

# Search by name starting with "test"
GET /api/mymodel/?name=test*

# Search by name containing "important"
GET /api/mymodel/?name=*important*

# Filter by age >= 18
GET /api/mymodel/?age=>=18

# Filter by age between 18 and 30
GET /api/mymodel/?age=18-30

# Multiple filters combined
GET /api/mymodel/?name=test*&age=>=18&status=active

# ForeignKey lookup
GET /api/mymodel/?category__name=electronics*

Pagination

Results are paginated by default (20 items per page, max 100).

Pagination Parameters

  • page - Page number (default: 1)
  • page_size - Items per page (default: 20, max: 100)

Paginated Response Format

{
  "count": 150,
  "next": "http://example.com/api/mymodel/?page=2",
  "previous": null,
  "results": [
    {
      "id": 1,
      "name": "Item 1",
      ...
    },
    ...
  ]
}

🤝 Contributing

If you have a helpful tool, pattern, or improvement to suggest: Fork the repo
Create a new branch
Submit a pull request
I welcome additions that promote clean, productive, and maintainable development.


🙏 Thanks

Thanks for exploring this repository!
Happy coding!

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_easy_crud-0.0.1.tar.gz (13.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_easy_crud-0.0.1-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file drf_easy_crud-0.0.1.tar.gz.

File metadata

  • Download URL: drf_easy_crud-0.0.1.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for drf_easy_crud-0.0.1.tar.gz
Algorithm Hash digest
SHA256 ef1e75efffdad11b7b1b01ee2beec977a99fc7c75db1758510b2797acbbc1dac
MD5 89af40e2d89ab9311f167a7a715d581d
BLAKE2b-256 84039f9b801d157e0a913e46c3f36462d4ab8e6c8a5d1ee1caac5e0723188116

See more details on using hashes here.

File details

Details for the file drf_easy_crud-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: drf_easy_crud-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for drf_easy_crud-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e4d22f7278243280c0a6d65acd3398b43c77a32a0df598d546ef06b01b2d80a5
MD5 dc4863ae46a4300e44e2e107b934feb5
BLAKE2b-256 d174196d69e54ab3898a3467c98e9b695abcb65a200453a32440b8afc1be2986

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