Skip to main content

Djangospice API

Reusable API utilities for Django and Django REST Framework.

Djangospice API provides reusable serializers, API routing utilities, permissions, and common ViewSet functionality for building consistent and modular Django REST APIs.


Features

  • Automatic API router discovery
  • Modular application-level API routers
  • Central API routing
  • Automatic model-based ViewSet registration
  • OpenAPI/Swagger tags
  • Default API model permissions
  • Action-aware serializers
  • Nested relationship serialization
  • Relationship ID and nested writes
  • Generic related-object serialization
  • Standard option serializers
  • Bulk deletion support

Requirements

  • Python 3.12+
  • Django 5.0+
  • Django REST Framework 3.15+

Installation

pip install djangospice-api

Configuration

Add the package to your Django project:

INSTALLED_APPS = [
    # ...
    "djangospice_api",
]

Include the API URLs:

from django.urls import include, path


urlpatterns = [
    path("api/", include("djangospice_api.urls")),
]

Once configured, Djangospice API can discover API routers provided by installed applications automatically.


API Routers

Applications can expose their API endpoints through:

<application>/api/router.py

For example:

courses/
└── api/
    └── router.py

The router can be a standard Django REST Framework router:

from rest_framework.routers import DefaultRouter

from .views import CourseViewSet


router = DefaultRouter()

router.register(
    "courses",
    CourseViewSet,
    basename="course",
)

The application's routes are automatically included in the project's API.

For example:

/api/courses/
/api/courses/{id}/

Applications do not need to depend on the Djangospice runtime to define their routers.


APIRouter

Djangospice API provides APIRouter for applications that need additional routing functionality.

from djangospice_api.router import APIRouter

It supports:

  • model-based registration
  • automatic ViewSet registration
  • router composition
  • default API permissions
  • OpenAPI tags

A shared router instance is also provided:

from djangospice_api.router import router

Registering a Model ViewSet

A ViewSet can be registered using an application label and model name:

router.register_model(
    "students",
    "student",
    StudentViewSet,
)

A custom basename can be provided:

router.register_model(
    "students",
    "student",
    StudentViewSet,
    basename="students",
)

Automatic ViewSet Registration

For conventional ModelViewSets, the model can be detected from the ViewSet's queryset:

router.register_viewset(
    StudentViewSet,
)

For example:

class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

The API router derives the application and model information automatically.


API Permissions

Djangospice API provides a default model-based permission system.

When a ViewSet does not define its own permission classes, the API router can apply:

ApiModelPermissions

Custom permissions can be supplied during registration:

router.register_viewset(
    StudentViewSet,
    permission_classes=[
        IsAuthenticated,
    ],
)

Explicit permissions defined by a ViewSet are preserved unless registration specifies an override.


OpenAPI Documentation

When ViewSets are registered automatically, Djangospice API can provide OpenAPI tags for generated API documentation.

For example, application-based registration can produce tags such as:

Students
Courses
Billing

Custom tags can also be supplied:

router.register_viewset(
    StudentViewSet,
    swagger_tags=[
        "Academic",
        "Students",
    ],
)

This integrates with drf-spectacular.


BaseModelSerializer

BaseModelSerializer extends Django REST Framework's ModelSerializer with action-specific representations.

from djangospice_api.serializers import BaseModelSerializer

Example:

class CourseSerializer(BaseModelSerializer):

    class Meta:
        model = Course

        fields = [
            "id",
            "code",
            "name",
            "department",
            "description",
        ]

        list_fields = [
            "id",
            "code",
            "name",
            "department",
        ]

        detail_fields = [
            "id",
            "code",
            "name",
            "department",
            "description",
        ]

Different field configurations can be provided for:

  • list
  • detail
  • create
  • update
  • partial update

When an action-specific configuration is not supplied, the standard fields configuration is used.


Flattening Relationships

Relationships can be represented as human-readable values in list responses.

class CourseSerializer(BaseModelSerializer):

    class Meta:
        model = Course

        fields = [
            "id",
            "code",
            "name",
            "department",
        ]

        flatten_fields = [
            "department",
        ]

A list response can then represent the department using its string representation rather than only its primary key.

This is useful for:

  • data tables
  • administrative interfaces
  • lookup interfaces
  • HTMX applications
  • JavaScript clients

Hidden List Fields

Fields can be excluded from list responses:

class Meta:
    model = Course

    fields = [
        "id",
        "code",
        "name",
        "description",
        "created_at",
    ]

    hidden_fields = [
        "description",
        "created_at",
    ]

The fields remain available to other serializer actions.


GenericObjectRelatedField

GenericObjectRelatedField provides a generic representation of related objects.

from djangospice_api.serializers import GenericObjectRelatedField

A related object is represented using:

{
    "id": 42,
    "model_type": "Course",
    "display_name": "Database Systems"
}

This is useful when an API works with generic or polymorphic relationships.


NestedModelSerializer

NestedModelSerializer extends BaseModelSerializer with support for Django model relationships.

from djangospice_api.serializers import NestedModelSerializer

It supports:

  • ForeignKey
  • OneToOneField
  • ManyToManyField

Nested serializers can be discovered using conventional serializer names or explicitly configured.

Example:

class CourseSerializer(NestedModelSerializer):

    class Meta:
        model = Course

        fields = [
            "id",
            "code",
            "name",
            "department",
        ]

Nested Serializer Configuration

Nested serializers can be explicitly specified:

class CourseSerializer(NestedModelSerializer):

    class Meta:
        model = Course

        fields = [
            "id",
            "code",
            "name",
            "department",
        ]

        serializers = {
            "department": DepartmentSerializer,
        }

This is useful when a model has multiple possible serializers.


Relationship Writes

Djangospice API provides consistent conventions for relationship writes.

Relationship Write field
ForeignKey field_id
OneToOne field_id
ManyToMany field_ids
Nested ForeignKey field_nested
Nested OneToOne field_nested
Nested ManyToMany field_nested

For example:

{
    "name": "Advanced Databases",
    "prerequisites_ids": [
        10,
        11,
        12
    ]
}

Nested relationships can also be supplied:

{
    "name": "Advanced Databases",
    "prerequisites_nested": [
        {
            "id": 10
        },
        {
            "name": "Data Structures"
        }
    ]
}

OptionModelSerializer

OptionModelSerializer provides a standard serializer for option and reference models.

from djangospice_api.serializers import OptionModelSerializer

The standard fields are:

id
name
value
slug
code
description
is_visible

Example:

class StatusSerializer(OptionModelSerializer):

    class Meta:
        model = Status

This is useful for:

  • dropdown options
  • lookup values
  • status definitions
  • configuration data
  • reference data

BulkDeleteMixin

BulkDeleteMixin adds bulk deletion support to Django REST Framework ViewSets.

from djangospice_api.mixins import BulkDeleteMixin

Example:

class CourseViewSet(
    BulkDeleteMixin,
    ModelViewSet,
):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

The ViewSet provides:

POST /courses/bulk-delete/

Request:

{
    "ids": [
        1,
        2,
        3
    ]
}

Response:

{
    "deleted": 3
}

Example

A typical Django application can combine the utilities:

from rest_framework.routers import DefaultRouter
from rest_framework.viewsets import ModelViewSet

from djangospice_api.mixins import BulkDeleteMixin

from .models import Course
from .serializers import CourseSerializer


class CourseViewSet(
    BulkDeleteMixin,
    ModelViewSet,
):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer


router = DefaultRouter()

router.register(
    "courses",
    CourseViewSet,
    basename="course",
)

Place the router in:

courses/api/router.py

and it will be discovered automatically.


Development

Clone the repository:

git clone https://github.com/briansimpo/djangospice_api.git
cd djangospice_api

Create a virtual environment:

python -m venv .venv

Activate the environment and install the package:

pip install -e .

License

This package is licensed under the MIT License.

See LICENSE for the full license text.

Metadata

Release files for djangospice-api 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for djangospice-api 0.2.0
File Size Uploaded Provenance Actions
djangospice_api-0.2.0.tar.gz 12.2 kB With provenance Details for djangospice_api-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for djangospice-api 0.2.0
File Interpreter ABI Platform Actions
djangospice_api-0.2.0-py3-none-any.whl Python 3 none any Details for djangospice_api-0.2.0-py3-none-any.whl

Total release size: 26.8 kB

Release files / djangospice_api-0.2.0.tar.gz

Download URL djangospice_api-0.2.0.tar.gz
Size 12.2 kB
Tags Source
SHA-256 checksum
How to use checksums
280dd26dfd0aa904125603c1e5aab944ca2985206c14c13e92d1c449b7d9fb6a
BLAKE2b-256 checksum
How to use checksums
9b7e1369b374d0e56fba57861d307bbf2167acdb12369352821ebc8a443ae818
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / djangospice_api-0.2.0-py3-none-any.whl

Download URL djangospice_api-0.2.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a4db7ceb9394e7eec66fb502592ff947276a59ee4327bfe2f9d77e8177a1111d
BLAKE2b-256 checksum
How to use checksums
ea6b4f52ec52ae53f049f149ac09290363c0be05e2bdeb520499053525413072
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Security for djangospice-api 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for djangospice_api-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page