Name | djresttoolkit JSON |
Version |
0.17.3
JSON |
| download |
home_page | None |
Summary | A collection of Django and DRF utilities to simplify API development. |
upload_time | 2025-08-24 07:25:22 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.13 |
license | # MIT License Copyright (c) 2025 Shailesh Pandit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
api-development
django
django-authentication
django-email
django-helpers
django-mixins
django-pagination
django-rest
django-rest-framework-utilities
django-rest-utilities
django-serializers
django-shortcuts
django-utilities
djangorestframework
drf
python-package
rest-api
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# π οΈ djresttoolkit (django rest toolkit)
[](https://pypi.org/project/djresttoolkit/)
[](https://pypi.org/project/djresttoolkit/)
[](https://github.com/shaileshpandit141/djresttoolkit/blob/main/LICENSE)
djresttoolkit is a collection of utilities and helpers for Django and Django REST Framework (DRF) that simplify common development tasks such as API handling, authentication, and email sending and much more.
## π Feature Index (djresttoolkit)
- **DB Seed Command (`dbseed`)**
Seed your database with fake data using Pydantic models powered by **Faker**. Supports relationships, transactions, and a `manage.py dbseed` command.
- **DB Flush Command (`dbflush`)**
Management command to flush all models or a specific model, resetting auto-increment IDs safely with transaction support.
- **EnvBaseSettings**
Typed settings loader using **YAML + .env**, supports nested keys and overrides. Great for structured configuration management.
- **EmailSender**
Custom class to send templated emails (`text` and `html`) with context. Supports error handling and logging.
- **Custom DRF Exception Handler**
Centralized error handler for DRF that extends default behavior and adds throttle support (`429 Too Many Requests` with retry info).
- **Response Time Middleware**
Middleware to measure, log, and inject `X-Response-Time` headers into every response.
- **Throttle**
- `ThrottleInfoJSONRenderer`: Automatically adds throttle headers to responses.
- `ThrottleInspector`: Inspect view/request throttling and attach structured headers.
- **AbsoluteUrlFileMixin**
DRF serializer mixin that converts `FileField` / `ImageField` URLs to **absolute URLs** automatically.
- **BulkCreateMixin**
Serializer mixin that enables **bulk creation** of objects and syncs field error messages with model fields.
- **ModelChoiceFieldMixin**
Retrieve choice fields (`TextChoices`, etc.) from Django models as structured dictionaries for API responses.
- **ChoiceFieldsAPIView**
Generic API view that exposes model `choices` in a REST-friendly JSON format.
- **RetrieveObjectMixin**
Lightweight mixin to fetch a single object from a queryset with filters, raising a custom error if `queryset` is not defined.
- **build\_absolute\_uri**
Helper to build full absolute URLs for named routes with optional query params. Works with Django + DRF requests.
- **PageNumberPagination**
Custom paginator with a structured `"page"` metadata block and support for dynamic `page-size` query param.
- **PaginatedDataBuilder**
Builder that combines `PageNumberPagination` + serializers to return standardized paginated responses with `"page"` + `"results"`.
- **Caching Mixins**
This module provides a set of DRF mixins to handle caching for `list`, `retrieve`, and `custom actions` with automatic invalidation on create, update, and destroy.
## π¦ Installation
- **By using uv:**
```bash
uv add djresttoolkit
````
- **By using pip:**
```bash
pip install djresttoolkit
````
## π All API Reference
### 1. DB Seed Command β API Reference
#### `Generator`
```python
from djresttoolkit.dbseed.models import Generator, Gen, Field
```
- `Gen`: Pre-initialized **Faker** instance for generating fake data.
- `Field`: Alias for `pydantic.Field` to define seed model fields.
#### Example
```python
from djresttoolkit.dbseed.models import SeedModel
from myapp.models import User
class UserSeedModel(SeedModel):
__model__ = User
username: str = Field(default_factory=lambda: Gen.user_name())
email: str = Field(default_factory=lambda: Gen.email())
```
#### `manage.py` Command: `dbseed`
Seed the database from all `dbseed` directories in installed apps.
```bash
python manage.py dbseed [--count 5] [--model User] [--seed 42]
```
#### Options
- `--count`: Number of records per model (default: 5).
- `--model`: Specific model name to seed (optional).
- `--seed`: Faker seed for reproducible data (optional).
#### Behavior
- Auto-discovers all `dbseed` models in installed apps.
- Handles ForeignKey, OneToOneField, and ManyToMany relationships.
- Uses transactions to ensure safe creation of records.
- Logs errors for failed instance creation but continues seeding.
#### Command Example
```bash
# Seed 10 records for all models
python manage.py dbseed --count 10
# Seed only the User model with fixed Faker seed
python manage.py dbseed --model User --seed 42
```
Hereβs a **concise API reference** for your database flush management command for `djresttoolkit`:
---
### 2. DB Flush Command β API Reference
```python
from djresttoolkit.management.commands import flush
```
#### `manage.py dbflush`
Command to **delete all records** from the database for all models or a specific model and **reset auto-increment IDs**.
#### Usage
```bash
python manage.py flush [--model ModelName] [--yes]
```
#### dbflush command options
- `--model`: Name of the model to flush (case-sensitive, e.g., `User`). If omitted, flushes all models.
- `--yes`: Skip confirmation prompt. Without this, the command asks for confirmation before deleting.
#### dbflush command behavior
- Deletes all records for the specified model or all models.
- Resets primary key sequences for supported databases:
- PostgreSQL: `ALTER SEQUENCE ... RESTART WITH 1`
- SQLite: Deletes from `sqlite_sequence` table
- Others: Logs a warning (not implemented).
- Uses transactions to ensure safe operations.
#### dbflush command example
```bash
# Flush all models with confirmation
python manage.py dbflush
# Flush a specific model (User) with confirmation
python manage.py dbflush --model User
# Flush all models without prompt
python manage.py dbflush --yes
```
#### Output
```bash
Flushed 10 records from model "User" and reset IDs.
```
or
```bash
Flushed 120 records from all models and reset IDs.
```
### 3. EnvBaseSettings β API Reference
```python
from djresttoolkit.envconfig import EnvBaseSettings
```
#### `EnvBaseSettings`
A **base settings class** for managing application configuration using:
- YAML files (default `.environ.yaml`)
- Environment variables (default `.env`)
Supports **nested configuration** using double underscores (`__`) in environment variable names.
#### Class Attributes
- Attributes
- `env_file`
- Type: `str`
- Default: `.env`
- Description: Environment variable file path.
- `yaml_file`
- Type: `str`
- Default: `.environ.yaml`
- Description: YAML configuration file path.
- `model_config`
- Type: `SettingsConfigDict`
- Description: Pydantic settings configuration (file encoding, nested delimiter).
#### Methods
#### `load(cls, *, env_file: str | None = None, ymal_file: str | None = None, warning: bool = True) -> EnvBaseSettings`
Loads configuration from **YAML first**, then overrides with **environment variables**.
#### Parameters
- `env_file` β Optional custom `.env` file path.
- `ymal_file` β Optional custom YAML file path.
- `warning` β Emit a warning if YAML file is missing (default `True`).
#### Returns
- Instance of `EnvBaseSettings` (or subclass) with loaded configuration.
#### Raises
- `UserWarning` if YAML file not found and `warning=True`.
### Usage Example
```python
from djresttoolkit.envconfig import EnvBaseSettings
class EnvSettings(EnvBaseSettings["EnvSettings"]):
debug: bool = False
database_url: str
# Load settings
settings = EnvSettings.load(warning=False)
print(settings.debug)
print(settings.database_url)
```
#### Features
- Prioritizes `.env` variables over YAML.
- Supports nested keys: `DATABASE__HOST`:- `settings.database.host`.
- Designed to be subclassed for project-specific settings.
### 4. EmailSender β API Reference
```python
from djresttoolkit.mail import EmailSender, EmailContent, EmailTemplate
```
### `EmailSender`
Send templated emails.
#### Init
```python
EmailSender(email_content: EmailContent | EmailContentDict)
```
#### EmailSender Methods
```python
send(to: list[str], exceptions: bool = False) -> bool
```
- `to`: recipient emails
- `exceptions`: raise on error if `True`, else logs error
- Returns `True` if sent, `False` on failure
#### Example for sending an email
```python
content = EmailContent(
subject="Hello",
from_email="noreply@example.com",
context={"username": "Alice"},
template=EmailTemplate(
text="emails/welcome.txt",
html="emails/welcome.html"
)
)
EmailSender(content).send(to=["user@example.com"])
```
#### `EmailContent`
- `subject`, `from_email`, `context`, `template` (EmailTemplate)
#### `EmailTemplate`
- `text`, `html` β template file paths
### 5. Custom DRF Exception Handler β API Reference
```python
from djresttoolkit.views import exception_handler
```
### `exception_handler(exc: Exception, context: dict[str, Any]) -> Response | None`
A DRF exception handler that:
- Preserves DRFβs default exception behavior.
- Adds throttling support (defaults to `AnonRateThrottle`).
- Returns **429 Too Many Requests** with `retry_after` if throttle limit is exceeded.
#### Exception Handler Parameters
- `exc`: Exception object.
- `context`: DRF context dictionary containing `"request"` and `"view"`.
#### Returns Type of Exception Handler
- `Response` β DRF Response object (with throttling info if applicable), or `None`.
#### Settings Configuration
In `settings.py`:
```python
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'djresttoolkit.views.exception_handler',
# Other DRF settings...
}
```
#### Throttle Behavior
- Uses `view.throttle_classes` if defined, else defaults to `AnonRateThrottle`.
- Tracks requests in cache and calculates `retry_after`.
- Cleans expired timestamps automatically.
### 6. Response Time Middleware β API Reference
```python
from djresttoolkit.middlewares import ResponseTimeMiddleware
```
### `ResponseTimeMiddleware`
Middleware to calculate and log **HTTP response time** for each request.
#### Constructor from ResponseTimeMiddleware
```python
ResponseTimeMiddleware(get_response: Callable[[HttpRequest], HttpResponse])
```
- `get_response`: The next middleware or view callable.
#### Response Time Middleware Usage
Add it to your Django `MIDDLEWARE` in `settings.py`:
```python
MIDDLEWARE = [
# Other middlewares...
'djresttoolkit.middlewares.ResponseTimeMiddleware',
]
```
#### Response Time Middleware Behavior
- Measures the time taken to process each request.
- Adds a header `X-Response-Time` to each HTTP response.
- Logs the response time using Django's logging system.
#### The response headers will include
```json
X-Response-Time: 0.01234 seconds
```
#### Logs a message
```bash
INFO: Request processed in 0.01234 seconds
```
### 7. Throttle β API Reference
#### `ThrottleInfoJSONRenderer`
```python
from djresttoolkit.renderers import ThrottleInfoJSONRenderer
```
A custom DRF JSON renderer that **automatically attaches throttle information to response headers**.
#### Usage (settings.py)
```python
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": [
"djresttoolkit.renderers.ThrottleInfoJSONRenderer",
"rest_framework.renderers.BrowsableAPIRenderer",
],
}
```
When enabled, every response includes throttle headers like:
```plaintext
X-Throttle-User-Limit: 100
X-Throttle-User-Remaining: 98
X-Throttle-User-Reset: 2025-08-18T07:30:00Z
X-Throttle-User-Retry-After: 0
```
#### `ThrottleInspector`
```python
from djresttoolkit.throttling import ThrottleInspector
```
Utility class to **inspect DRF throttle usage** for a view or request.
#### Constructor for ThrottleInspector
```python
ThrottleInspector(
view: APIView,
request: Request | None = None,
throttle_classes: list[type[BaseThrottle]] | None = None,
)
```
#### Key Methods
- `get_details() -> dict[str, Any]`
Returns structured throttle info: limit, remaining, reset time, retry\_after.
- `attach_headers(response: Response, throttle_info: dict | None)`
Attaches throttle data to HTTP headers.
### 8. AbsoluteUrlFileMixin β API Reference
```python
from djresttoolkit.serializers.mixins import AbsoluteUrlFileMixin
```
### `AbsoluteUrlFileMixin`
A **serializer mixin** that converts **FileField** and **ImageField** URLs to **absolute URLs**, ensuring compatibility with cloud storage backends.
---
### Attributes
- `file_fields`
- type: `list[str] | None`
- default: `None`
- description: Manual list of file field names for non-model serializers.
### Absolute Url File Mixin Methods
#### `to_representation(self, instance: Any) -> dict[str, Any]`
- Overrides default serializer `to_representation`.
- Enhances all file-related fields in the serialized output to **absolute URLs**.
#### `enhance_file_fields(self, instance: Any, representation: dict[str, Any], request: Any) -> dict[str, Any]`
- Core logic to process each file field.
- Converts relative URLs to absolute URLs using `request.build_absolute_uri()`.
- Supports model serializers or manual `file_fields`.
- Logs warnings if request context is missing or file is not found.
#### Exceptions
- `MissingRequestContext`: Raised if the request object is missing in serializer context and `DEBUG=True`.
### Absolute Url File Mixin Example
```python
from rest_framework import serializers
from djresttoolkit.serializers.mixins import AbsoluteUrlFileMixin
from myapp.models import Document
class DocumentSerializer(AbsoluteUrlFileMixin, serializers.ModelSerializer):
class Meta:
model = Document
fields = ["id", "title", "file"]
# Output will convert `file` field to an absolute URL
serializer = DocumentSerializer(instance, context={"request": request})
data = serializer.data
```
#### Notes
- Works with both Django model serializers and custom serializers.
- Relative file paths are automatically converted to absolute URLs.
- Can manually specify fields via `file_fields` for non-model serializers.
### 9. BulkCreateMixin β API Reference
```python
from djresttoolkit.serializers.mixins import BulkCreateMixin
```
#### `BulkCreateMixin`
A **DRF serializer mixin** that adds support for:
- **Single instance creation** with extra context fields
- **Bulk creation** from a list of validated data dictionaries
- **Updating serializer field error messages** with model-specific messages
#### Bulk Create Mixin Notes
- `bulk_create()` does **not trigger model signals** or call `.save()` on instances.
- `Meta.model` **must** be defined in the serializer.
#### Bulk Create Mixin Methods
#### `create(self, validated_data: dict[str, Any] | list[dict[str, Any]]) -> Model | list[Model]`
- Creates single or multiple model instances.
- **Parameters:**
- `validated_data`: dict for single instance or list of dicts for bulk creation.
- **Returns:**
- Single model instance or list of instances.
- **Raises:**
- `AttributeError` if `Meta.model` is not defined.
- `NotImplementedError` if used with a serializer that does not implement `create()`.
#### `get_fields(self) -> dict[str, SerializerField]`
- Extends DRF serializer `get_fields()` to update **error messages** using model field definitions.
- **Returns:**
- Dictionary of serializer fields.
- **Warning:**
- Logs a warning if a serializer field is not present on the model.
### Bulk Create Mixin Example
```python
from rest_framework import serializers
from djresttoolkit.serializers.mixins import BulkCreateMixin
from myapp.models import Product
class ProductSerializer(BulkCreateMixin, serializers.ModelSerializer):
class Meta:
model = Product
fields = ["id", "name", "price"]
# Single creation
serializer = ProductSerializer(data={"name": "Item1", "price": 10})
serializer.is_valid(raise_exception=True)
product = serializer.save()
# Bulk creation
serializer = ProductSerializer(
data=[
{"name": "Item2", "price": 20},
{"name": "Item3", "price": 30},
],
many=True
)
serializer.is_valid(raise_exception=True)
products = serializer.save()
```
#### Bulk Create Mixin Features
- Works seamlessly with DRF `ModelSerializer`.
- Automatically updates field error messages based on Django model definitions.
- Bulk creation is optimized using `model.objects.bulk_create()` for efficiency.
### 10. ModelChoiceFieldMixin β API Reference
```python
from djresttoolkit.models.mixins import ModelChoiceFieldMixin
```
### `ModelChoiceFieldMixin`
A **Django model mixin** to retrieve **choice fields** from a model, designed to work seamlessly with Django's `TextChoices`.
#### Class Attributes in Model Choice Field Mixin
- `model: type[Model] | None` β The Django model class to inspect. **Must be set.**
- `choice_fields: list[str] | None` β List of model field names that contain choices. **Must be set.**
#### Model Choice Field Mixin Methods
- `get_choices() -> dict[str, dict[str, str]]`
Retrieve the choice fields from the model as a dictionary.
- **Returns:**
```python
{
"field_name": {
"choice_value": "Choice Label",
...
},
...
}
```
- **Raises:**
- `AttributeDoesNotExist` β If `model` or `choice_fields` is not set.
- `ChoiceFieldNotFound` β If a field does not exist, has no choices, or has invalid choice format.
---
### Model Choice Field Mixin Example
```python
from django.db import models
from djresttoolkit.serializers.mixins import ModelChoiceFieldMixin
class Product(models.Model):
class Status(models.TextChoices):
DRAFT = "draft", "Draft"
PUBLISHED = "published", "Published"
status = models.CharField(max_length=20, choices=Status.choices)
category = models.CharField(max_length=50, choices=[
("a", "Category A"),
("b", "Category B"),
])
class ProductChoiceMixin(ModelChoiceFieldMixin):
model = Product
choice_fields = ["status", "category"]
choices = ProductChoiceMixin.get_choices()
print(choices)
# Output:
# {
# "status": {"draft": "Draft", "published": "Published"},
# "category": {"a": "Category A", "b": "Category B"}
# }
```
#### Features of Model Choice Field Mixin
- Safely validates that fields exist and have valid choices.
- Returns a ready-to-use dictionary mapping values to labels.
- Ideal for DRF serializers, forms, and admin customization.
Hereβs a concise **docs entry** for your `ChoiceFieldsAPIView` suitable for `djresttoolkit` documentation:
---
### 11. ChoiceFieldsAPIView β API Reference
```python
from djresttoolkit.views import ChoiceFieldsAPIView
```
#### `ChoiceFieldsAPIView`
A **generic DRF API view** to return all choices for specified model fields.
#### Class Attributes of Choice Fields APIView
- `model_class: type[Model] | None` β The Django model to inspect. **Must be set.**
- `choice_fields: list[str] | None` β List of fields on the model with choices. **Must be set.**
---
#### Choice Fields APIView Methods
- `get(request: Request) -> Response`
Fetches the choices for the configured model fields.
- **Returns:**
- `200 OK` β JSON object containing all choices:
```json
{
"choices": {
"status": {"draft": "Draft", "published": "Published"},
"category": {"a": "Category A", "b": "Category B"}
}
}
```
- `400 Bad Request` β If any error occurs while retrieving choices.
- **Raises:**
- `AttributeDoesNotExist` β If `model_class` or `choice_fields` is not set.
---
### Example of Choice Fields APIView
```python
from django.urls import path
from djresttoolkit.views import ChoiceFieldsAPIView
from myapp.models import Product
class ProductChoiceAPI(ChoiceFieldsAPIView):
model_class = Product
choice_fields = ["status", "category"]
urlpatterns = [
path(
"api/v1/product-choices/",
ProductChoiceAPI.as_view(),
name="product-choices"
),
]
```
#### Choice Fields APIView Features
- Dynamically returns all choices for selected fields in a model.
- Useful for frontend forms or API consumers that need selectable options.
- Integrates seamlessly with `ModelChoiceFieldMixin` from `djresttoolkit`.
### 12. RetrieveObjectMixin β API Reference
```python
from djresttoolkit.views.mixins import RetrieveObjectMixin
```
#### `RetrieveObjectMixin[T: Model]`
A **generic mixin** to retrieve a single Django model instance by filters.
#### Class Attributes of Retrieve Object Mixin
- `queryset: QuerySet[T] | None` β The queryset used to retrieve objects. **Must be set.**
#### Raises of Retrieve Object Mixin
- `QuerysetNotDefinedError` β If `queryset` is not set in the class.
#### Retrieve Object Mixin Methods
- `get_object(**filters: Any) -> T | None`
Retrieve a single model object using the provided filter criteria.
- **Parameters:**
- `**filters` β Keyword arguments to filter the queryset (e.g., `id=1`, `slug="abc"`).
- **Returns:**
- Model instance matching the filters, or `None` if no match is found.
#### Example of Retrieve Object Mixin
```python
from rest_framework.views import APIView
from django.http import JsonResponse
from myapp.models import Book
from djresttoolkit.mixins import RetrieveObjectMixin
class BookDetailView(RetrieveObjectMixin[Book], APIView):
queryset = Book.objects.all()
def get(self, request, *args, **kwargs):
book = self.get_object(id=kwargs["id"])
if book:
return JsonResponse({"title": book.title, "author": book.author})
return JsonResponse({"detail": "Not found"}, status=404)
```
#### Features of Retrieve Object Mixin
- Simplifies object retrieval in class-based views or DRF views.
- Returns `None` instead of raising `DoesNotExist`, making error handling easier.
- Works with any Django model and queryset.
### 13. build_absolute_uri β API Reference
```python
from djresttoolkit.urls import build_absolute_uri
```
#### build absolute uri Description
- Builds a **fully qualified absolute URL** for a Django or DRF view.
- Optionally includes **query parameters**.
- Works with both **Django `HttpRequest`** and **DRF `Request`** objects.
- Uses Django's `reverse()` to dynamically resolve URL names.
#### build absolute uri Function Signature
```python
def build_absolute_uri(
request: HttpRequest | Request,
url_name: str,
query_params: dict[str, Any] | None = None,
*args: Any,
**kwargs: Any,
) -> str:
...
```
---
#### build absolute uri Parameters
- `request` (`HttpRequest | Request`): The incoming Django or DRF request object.
- `url_name` (`str`): Name of the URL pattern to reverse.
- `query_params` (`dict[str, Any] | None`): Optional dictionary of query parameters to append to the URL.
- `*args` (`Any`): Positional arguments for the URL reversal.
- `**kwargs` (`Any`): Keyword arguments for the URL reversal.
---
### build absolute uri Returns
- `str`: Absolute URI of the view including optional query parameters.
### Example of build absolute uri
```python
from django.http import HttpRequest
from djresttoolkit.utils import build_absolute_uri
def my_view(request: HttpRequest):
absolute_url = build_absolute_uri(
request,
url_name="book-detail",
query_params={"ref": "newsletter"},
pk=123
)
return HttpResponse(f"URL: {absolute_url}")
```
**Output Example:**
```url
https://example.com/api/books/123/?ref=newsletter
```
### 14. PageNumberPagination β API Reference
```python
from djresttoolkit.pagination import PageNumberPagination
```
#### Description of Page Number Pagination
- Extends **DRFβs `PageNumberPagination`** with a **cleaner metadata structure**.
- Adds support for **dynamic page size** via the `page-size` query parameter.
- Returns pagination metadata inside a `"page"` object, separate from `"results"`.
#### Features of Page Number Pagination
- Clients can control items per page using `?page-size=`.
- Structured pagination metadata:
- `current`:- current page number
- `total`:- total number of pages
- `size`:- number of items per page
- `total_items`:- total number of items across all pages
- `next`:- next page URL
- `previous`:- previous page URL
- Standardized API response format.
### Attributes of Page Number Pagination
- `page_size_query_param: str`:- Query parameter name (`"page-size"`).
### Page Number Pagination Methods
- `get_paginated_response(data: Any) -> Response`
Returns a JSON response with both pagination metadata and results.
### Example Response of Page Number Pagination
```json
{
"page": {
"current": 1,
"total": 10,
"size": 20,
"total_items": 200,
"next": "http://api.example.com/items/?page=2&page-size=20",
"previous": null
},
"results": [
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
]
}
```
### 15. PaginatedDataBuilder β API Reference
```python
from djresttoolkit.pagination import PaginatedDataBuilder
```
---
#### Description of Paginated Data Builder
- A **builder utility** to paginate and serialize Django QuerySets using DRF.
- Uses the custom **`PageNumberPagination`** class for consistent pagination responses.
- Designed for reusability inside DRF views and APIs.
#### Features of Paginated Data Builder
- Integrates with **DRF serializers**.
- Handles **invalid pages** gracefully by raising `NotFound`.
- Returns both:
- `"page"`:- pagination metadata
- `"results"`:- serialized data.
- Provides **structured pagination response format**.
---
#### Initialization of Paginated Data Builder
```python
builder = PaginatedDataBuilder(
request=request,
serializer_class=MySerializer,
queryset=MyModel.objects.all()
)
```
- `request: Request`:- DRF request object.
- `serializer_class: type[BaseSerializer]`:- DRF serializer class for the model.
- `queryset: QuerySet`:- Django queryset to paginate.
### Paginated Data Builder Methods
- `get_paginated_data() -> dict[str, Any]`
- Applies pagination to the queryset.
- Serializes the paginated results.
- Returns a dictionary with `"page"` and `"results"`.
- Raises `NotFound` if no page data is found.
### Example Response of Paginated Data Builder
```json
{
"page": {
"current": 2,
"total": 5,
"size": 20,
"total_items": 100,
"next": "http://api.example.com/items/?page=3&page-size=20",
"previous": "http://api.example.com/items/?page=1&page-size=20"
},
"results": [
{ "id": 21, "name": "Item 21" },
{ "id": 22, "name": "Item 22" }
]
}
```
### 16. Caching Mixins β API Reference
This module provides a set of DRF mixins to handle **caching for list, retrieve, and custom actions** with automatic invalidation on create, update, and destroy.
#### 1οΈ `CacheKeyMixin`
- **Purpose**: Generate unique cache keys for DRF viewset actions.
- **Attributes**:
- `cache_timeout: int = 300`:- default cache duration in seconds.
- **Methods**:
- `get_cache_timeout()`:- returns the cache timeout.
- `get_cache_key(action_type, pk=None, action_name=None)`:- returns a cache key string based on action type:**
- `list` or `custom-list`:- hash of query parameters.
- `retrieve` or `custom-detail`:- uses primary key (`pk`).
#### 2οΈ `CacheOpsMixin`
- **Purpose**: Get, set, and invalidate cache.
- **Methods**:
- `get_or_set_cache(cache_key, data_fn, timeout=None)`:- fetch from cache or compute and set.
- `invalidate_cache(pk=None, custom_actions=None)`:- delete cached items:
- Deletes retrieve/detail caches for a `pk`.
- Deletes list caches (supports `delete_pattern` if available).
#### 3οΈ `CacheActionMixin`
- **Purpose**: Decorator for caching custom DRF `@action` methods.
- **Methods**:
- `cache_action(detail=False, action_name=None)`:- returns a decorator that caches action results automatically.
- Works for:
- `detail=False`:- custom-list action cache.
- `detail=True`:- custom-detail action cache.
#### 4οΈ `CacheListRetrieveMixin`
- **Purpose**: Caches DRF `list()` and `retrieve()` responses.
- **Methods**:
- `list(request, *args, **kwargs)`:- caches list responses.
- `retrieve(request, *args, **kwargs)`:- caches detail responses.
- `_get_list_data(request)`:- internal method to fetch paginated list data.
- `_get_detail_data()`:- internal method to fetch a single object.
#### 5οΈ `CacheInvalidateMixin`
- **Purpose**: Automatically invalidates caches on write operations.
- **Methods**:
- `create(request, *args, **kwargs)`:- invalidates list caches.
- `update(request, *args, **kwargs)`:- invalidates detail caches for `pk`.
- `destroy(request, *args, **kwargs)`:- invalidates detail caches for `pk`.
#### Example of Caching Mixins
```python
from rest_framework.viewsets import ModelViewSet
from myapp.models import Book
from myapp.serializers import BookSerializer
from djresttoolkit.cache.mixins import CacheInvalidateMixin, CacheActionMixin
class BookViewSet(CacheInvalidateMixin, ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
basename = "book"
@CacheActionMixin.cache_action(detail=False)
def popular(self, request):
data = Book.objects.filter(is_popular=True)
serializer = self.get_serializer(data, many=True)
return Response(serializer.data)
```
- Automatically caches `list`, `retrieve`, and `popular` actions.
- Invalidates caches when books are created, updated, or deleted.
- Supports custom cache keys per action.
## π οΈ Planned Features
- Add more utils
## π€ Contributing
Contributions are welcome! Please open an issue or PR for any improvements.
## π License
MIT License β See [LICENSE](LICENSE).
## π€ Author
For questions or assistance, contact **Shailesh** at [shaileshpandit141@gmail.com](mailto:shaileshpandit141@gmail.com).
Raw data
{
"_id": null,
"home_page": null,
"name": "djresttoolkit",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": null,
"keywords": "api-development, django, django-authentication, django-email, django-helpers, django-mixins, django-pagination, django-rest, django-rest-framework-utilities, django-rest-utilities, django-serializers, django-shortcuts, django-utilities, djangorestframework, drf, python-package, rest-api",
"author": null,
"author_email": "shaileshpandit141 <shaileshpandit141@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/eb/51/46b456b751474c94090de949763b7e0ddbd8df934358b9a541617da51dd8/djresttoolkit-0.17.3.tar.gz",
"platform": null,
"description": "# \ud83d\udee0\ufe0f djresttoolkit (django rest toolkit)\n\n[](https://pypi.org/project/djresttoolkit/)\n[](https://pypi.org/project/djresttoolkit/)\n[](https://github.com/shaileshpandit141/djresttoolkit/blob/main/LICENSE)\n\ndjresttoolkit is a collection of utilities and helpers for Django and Django REST Framework (DRF) that simplify common development tasks such as API handling, authentication, and email sending and much more.\n\n## \ud83d\udcd6 Feature Index (djresttoolkit)\n\n- **DB Seed Command (`dbseed`)**\n Seed your database with fake data using Pydantic models powered by **Faker**. Supports relationships, transactions, and a `manage.py dbseed` command.\n\n- **DB Flush Command (`dbflush`)**\n Management command to flush all models or a specific model, resetting auto-increment IDs safely with transaction support.\n\n- **EnvBaseSettings**\n Typed settings loader using **YAML + .env**, supports nested keys and overrides. Great for structured configuration management.\n\n- **EmailSender**\n Custom class to send templated emails (`text` and `html`) with context. Supports error handling and logging.\n\n- **Custom DRF Exception Handler**\n Centralized error handler for DRF that extends default behavior and adds throttle support (`429 Too Many Requests` with retry info).\n\n- **Response Time Middleware**\n Middleware to measure, log, and inject `X-Response-Time` headers into every response.\n\n- **Throttle**\n - `ThrottleInfoJSONRenderer`: Automatically adds throttle headers to responses.\n - `ThrottleInspector`: Inspect view/request throttling and attach structured headers.\n\n- **AbsoluteUrlFileMixin**\n DRF serializer mixin that converts `FileField` / `ImageField` URLs to **absolute URLs** automatically.\n\n- **BulkCreateMixin**\n Serializer mixin that enables **bulk creation** of objects and syncs field error messages with model fields.\n\n- **ModelChoiceFieldMixin**\n Retrieve choice fields (`TextChoices`, etc.) from Django models as structured dictionaries for API responses.\n\n- **ChoiceFieldsAPIView**\n Generic API view that exposes model `choices` in a REST-friendly JSON format.\n\n- **RetrieveObjectMixin**\n Lightweight mixin to fetch a single object from a queryset with filters, raising a custom error if `queryset` is not defined.\n\n- **build\\_absolute\\_uri**\n Helper to build full absolute URLs for named routes with optional query params. Works with Django + DRF requests.\n\n- **PageNumberPagination**\n Custom paginator with a structured `\"page\"` metadata block and support for dynamic `page-size` query param.\n\n- **PaginatedDataBuilder**\n Builder that combines `PageNumberPagination` + serializers to return standardized paginated responses with `\"page\"` + `\"results\"`.\n\n- **Caching Mixins**\n This module provides a set of DRF mixins to handle caching for `list`, `retrieve`, and `custom actions` with automatic invalidation on create, update, and destroy.\n\n## \ud83d\udce6 Installation\n\n- **By using uv:**\n \n ```bash\n uv add djresttoolkit\n ````\n\n- **By using pip:**\n\n ```bash\n pip install djresttoolkit\n ````\n\n## \ud83d\udcda All API Reference\n\n### 1. DB Seed Command \u2014 API Reference\n\n#### `Generator`\n\n```python\nfrom djresttoolkit.dbseed.models import Generator, Gen, Field\n```\n\n- `Gen`: Pre-initialized **Faker** instance for generating fake data.\n- `Field`: Alias for `pydantic.Field` to define seed model fields.\n\n#### Example\n\n```python\nfrom djresttoolkit.dbseed.models import SeedModel\nfrom myapp.models import User\n\nclass UserSeedModel(SeedModel):\n __model__ = User\n\n username: str = Field(default_factory=lambda: Gen.user_name())\n email: str = Field(default_factory=lambda: Gen.email())\n```\n\n#### `manage.py` Command: `dbseed`\n\nSeed the database from all `dbseed` directories in installed apps.\n\n```bash\npython manage.py dbseed [--count 5] [--model User] [--seed 42]\n```\n\n#### Options\n\n- `--count`: Number of records per model (default: 5).\n- `--model`: Specific model name to seed (optional).\n- `--seed`: Faker seed for reproducible data (optional).\n\n#### Behavior\n\n- Auto-discovers all `dbseed` models in installed apps.\n- Handles ForeignKey, OneToOneField, and ManyToMany relationships.\n- Uses transactions to ensure safe creation of records.\n- Logs errors for failed instance creation but continues seeding.\n\n#### Command Example\n\n```bash\n# Seed 10 records for all models\npython manage.py dbseed --count 10\n\n# Seed only the User model with fixed Faker seed\npython manage.py dbseed --model User --seed 42\n```\n\nHere\u2019s a **concise API reference** for your database flush management command for `djresttoolkit`:\n\n---\n\n### 2. DB Flush Command \u2014 API Reference\n\n```python\nfrom djresttoolkit.management.commands import flush\n```\n\n#### `manage.py dbflush`\n\nCommand to **delete all records** from the database for all models or a specific model and **reset auto-increment IDs**.\n\n#### Usage\n\n```bash\npython manage.py flush [--model ModelName] [--yes]\n```\n\n#### dbflush command options\n\n- `--model`: Name of the model to flush (case-sensitive, e.g., `User`). If omitted, flushes all models.\n- `--yes`: Skip confirmation prompt. Without this, the command asks for confirmation before deleting.\n\n#### dbflush command behavior\n\n- Deletes all records for the specified model or all models.\n- Resets primary key sequences for supported databases:\n\n - PostgreSQL: `ALTER SEQUENCE ... RESTART WITH 1`\n - SQLite: Deletes from `sqlite_sequence` table\n - Others: Logs a warning (not implemented).\n- Uses transactions to ensure safe operations.\n\n#### dbflush command example\n\n```bash\n# Flush all models with confirmation\npython manage.py dbflush\n\n# Flush a specific model (User) with confirmation\npython manage.py dbflush --model User\n\n# Flush all models without prompt\npython manage.py dbflush --yes\n```\n\n#### Output\n\n```bash\nFlushed 10 records from model \"User\" and reset IDs.\n```\n\nor\n\n```bash\nFlushed 120 records from all models and reset IDs.\n```\n\n### 3. EnvBaseSettings \u2014 API Reference\n\n```python\nfrom djresttoolkit.envconfig import EnvBaseSettings\n```\n\n#### `EnvBaseSettings`\n\nA **base settings class** for managing application configuration using:\n\n- YAML files (default `.environ.yaml`)\n- Environment variables (default `.env`)\n\nSupports **nested configuration** using double underscores (`__`) in environment variable names.\n\n#### Class Attributes\n\n- Attributes\n - `env_file`\n - Type: `str`\n - Default: `.env`\n - Description: Environment variable file path.\n - `yaml_file`\n - Type: `str`\n - Default: `.environ.yaml`\n - Description: YAML configuration file path.\n - `model_config`\n - Type: `SettingsConfigDict`\n - Description: Pydantic settings configuration (file encoding, nested delimiter).\n\n#### Methods\n\n#### `load(cls, *, env_file: str | None = None, ymal_file: str | None = None, warning: bool = True) -> EnvBaseSettings`\n\nLoads configuration from **YAML first**, then overrides with **environment variables**.\n\n#### Parameters\n\n- `env_file` \u2014 Optional custom `.env` file path.\n- `ymal_file` \u2014 Optional custom YAML file path.\n- `warning` \u2014 Emit a warning if YAML file is missing (default `True`).\n\n#### Returns\n\n- Instance of `EnvBaseSettings` (or subclass) with loaded configuration.\n\n#### Raises\n\n- `UserWarning` if YAML file not found and `warning=True`.\n\n### Usage Example\n\n```python\nfrom djresttoolkit.envconfig import EnvBaseSettings\n\nclass EnvSettings(EnvBaseSettings[\"EnvSettings\"]):\n debug: bool = False\n database_url: str\n\n# Load settings\nsettings = EnvSettings.load(warning=False)\n\nprint(settings.debug)\nprint(settings.database_url)\n```\n\n#### Features\n\n- Prioritizes `.env` variables over YAML.\n- Supports nested keys: `DATABASE__HOST`:- `settings.database.host`.\n- Designed to be subclassed for project-specific settings.\n\n### 4. EmailSender \u2014 API Reference\n\n```python\nfrom djresttoolkit.mail import EmailSender, EmailContent, EmailTemplate\n```\n\n### `EmailSender`\n\nSend templated emails.\n\n#### Init\n\n```python\nEmailSender(email_content: EmailContent | EmailContentDict)\n```\n\n#### EmailSender Methods\n\n```python\nsend(to: list[str], exceptions: bool = False) -> bool\n```\n\n- `to`: recipient emails\n- `exceptions`: raise on error if `True`, else logs error\n- Returns `True` if sent, `False` on failure\n\n#### Example for sending an email\n\n```python\ncontent = EmailContent(\n subject=\"Hello\",\n from_email=\"noreply@example.com\",\n context={\"username\": \"Alice\"},\n template=EmailTemplate(\n text=\"emails/welcome.txt\",\n html=\"emails/welcome.html\"\n )\n)\nEmailSender(content).send(to=[\"user@example.com\"])\n```\n\n#### `EmailContent`\n\n- `subject`, `from_email`, `context`, `template` (EmailTemplate)\n\n#### `EmailTemplate`\n\n- `text`, `html` \u2014 template file paths\n\n### 5. Custom DRF Exception Handler \u2014 API Reference\n\n```python\nfrom djresttoolkit.views import exception_handler\n```\n\n### `exception_handler(exc: Exception, context: dict[str, Any]) -> Response | None`\n\nA DRF exception handler that:\n\n- Preserves DRF\u2019s default exception behavior.\n- Adds throttling support (defaults to `AnonRateThrottle`).\n- Returns **429 Too Many Requests** with `retry_after` if throttle limit is exceeded.\n\n#### Exception Handler Parameters\n\n- `exc`: Exception object.\n- `context`: DRF context dictionary containing `\"request\"` and `\"view\"`.\n\n#### Returns Type of Exception Handler\n\n- `Response` \u2014 DRF Response object (with throttling info if applicable), or `None`.\n\n#### Settings Configuration\n\nIn `settings.py`:\n\n```python\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'djresttoolkit.views.exception_handler',\n # Other DRF settings...\n}\n```\n\n#### Throttle Behavior\n\n- Uses `view.throttle_classes` if defined, else defaults to `AnonRateThrottle`.\n- Tracks requests in cache and calculates `retry_after`.\n- Cleans expired timestamps automatically.\n\n### 6. Response Time Middleware \u2014 API Reference\n\n```python\nfrom djresttoolkit.middlewares import ResponseTimeMiddleware\n```\n\n### `ResponseTimeMiddleware`\n\nMiddleware to calculate and log **HTTP response time** for each request.\n\n#### Constructor from ResponseTimeMiddleware\n\n```python\nResponseTimeMiddleware(get_response: Callable[[HttpRequest], HttpResponse])\n```\n\n- `get_response`: The next middleware or view callable.\n\n#### Response Time Middleware Usage\n\nAdd it to your Django `MIDDLEWARE` in `settings.py`:\n\n```python\nMIDDLEWARE = [\n # Other middlewares...\n 'djresttoolkit.middlewares.ResponseTimeMiddleware',\n]\n```\n\n#### Response Time Middleware Behavior\n\n- Measures the time taken to process each request.\n- Adds a header `X-Response-Time` to each HTTP response.\n- Logs the response time using Django's logging system.\n\n#### The response headers will include\n\n```json\nX-Response-Time: 0.01234 seconds\n```\n\n#### Logs a message\n\n```bash\nINFO: Request processed in 0.01234 seconds\n```\n\n### 7. Throttle \u2014 API Reference\n\n#### `ThrottleInfoJSONRenderer`\n\n```python\nfrom djresttoolkit.renderers import ThrottleInfoJSONRenderer\n```\n\nA custom DRF JSON renderer that **automatically attaches throttle information to response headers**.\n\n#### Usage (settings.py)\n\n```python\nREST_FRAMEWORK = {\n \"DEFAULT_RENDERER_CLASSES\": [\n \"djresttoolkit.renderers.ThrottleInfoJSONRenderer\",\n \"rest_framework.renderers.BrowsableAPIRenderer\",\n ],\n}\n```\n\nWhen enabled, every response includes throttle headers like:\n\n```plaintext\nX-Throttle-User-Limit: 100\nX-Throttle-User-Remaining: 98\nX-Throttle-User-Reset: 2025-08-18T07:30:00Z\nX-Throttle-User-Retry-After: 0\n```\n\n#### `ThrottleInspector`\n\n```python\nfrom djresttoolkit.throttling import ThrottleInspector\n```\n\nUtility class to **inspect DRF throttle usage** for a view or request.\n\n#### Constructor for ThrottleInspector\n\n```python\nThrottleInspector(\n view: APIView,\n request: Request | None = None,\n throttle_classes: list[type[BaseThrottle]] | None = None,\n)\n```\n\n#### Key Methods\n\n- `get_details() -> dict[str, Any]`\n Returns structured throttle info: limit, remaining, reset time, retry\\_after.\n\n- `attach_headers(response: Response, throttle_info: dict | None)`\n Attaches throttle data to HTTP headers.\n\n### 8. AbsoluteUrlFileMixin \u2014 API Reference\n\n```python\nfrom djresttoolkit.serializers.mixins import AbsoluteUrlFileMixin\n```\n\n### `AbsoluteUrlFileMixin`\n\nA **serializer mixin** that converts **FileField** and **ImageField** URLs to **absolute URLs**, ensuring compatibility with cloud storage backends.\n\n---\n\n### Attributes\n\n- `file_fields`\n- type: `list[str] | None`\n- default: `None`\n- description: Manual list of file field names for non-model serializers.\n\n### Absolute Url File Mixin Methods\n\n#### `to_representation(self, instance: Any) -> dict[str, Any]`\n\n- Overrides default serializer `to_representation`.\n- Enhances all file-related fields in the serialized output to **absolute URLs**.\n\n#### `enhance_file_fields(self, instance: Any, representation: dict[str, Any], request: Any) -> dict[str, Any]`\n\n- Core logic to process each file field.\n- Converts relative URLs to absolute URLs using `request.build_absolute_uri()`.\n- Supports model serializers or manual `file_fields`.\n- Logs warnings if request context is missing or file is not found.\n\n#### Exceptions\n\n- `MissingRequestContext`: Raised if the request object is missing in serializer context and `DEBUG=True`.\n\n### Absolute Url File Mixin Example\n\n```python\nfrom rest_framework import serializers\nfrom djresttoolkit.serializers.mixins import AbsoluteUrlFileMixin\nfrom myapp.models import Document\n\nclass DocumentSerializer(AbsoluteUrlFileMixin, serializers.ModelSerializer):\n class Meta:\n model = Document\n fields = [\"id\", \"title\", \"file\"]\n\n# Output will convert `file` field to an absolute URL\nserializer = DocumentSerializer(instance, context={\"request\": request})\ndata = serializer.data\n```\n\n#### Notes\n\n- Works with both Django model serializers and custom serializers.\n- Relative file paths are automatically converted to absolute URLs.\n- Can manually specify fields via `file_fields` for non-model serializers.\n\n### 9. BulkCreateMixin \u2014 API Reference\n\n```python\nfrom djresttoolkit.serializers.mixins import BulkCreateMixin\n```\n\n#### `BulkCreateMixin`\n\nA **DRF serializer mixin** that adds support for:\n\n- **Single instance creation** with extra context fields\n- **Bulk creation** from a list of validated data dictionaries\n- **Updating serializer field error messages** with model-specific messages\n\n#### Bulk Create Mixin Notes\n\n- `bulk_create()` does **not trigger model signals** or call `.save()` on instances.\n- `Meta.model` **must** be defined in the serializer.\n\n#### Bulk Create Mixin Methods\n\n#### `create(self, validated_data: dict[str, Any] | list[dict[str, Any]]) -> Model | list[Model]`\n\n- Creates single or multiple model instances.\n- **Parameters:**\n - `validated_data`: dict for single instance or list of dicts for bulk creation.\n \n- **Returns:**\n - Single model instance or list of instances.\n \n- **Raises:**\n - `AttributeError` if `Meta.model` is not defined.\n - `NotImplementedError` if used with a serializer that does not implement `create()`.\n\n#### `get_fields(self) -> dict[str, SerializerField]`\n\n- Extends DRF serializer `get_fields()` to update **error messages** using model field definitions.\n- **Returns:**\n - Dictionary of serializer fields.\n\n- **Warning:**\n - Logs a warning if a serializer field is not present on the model.\n\n### Bulk Create Mixin Example\n\n```python\nfrom rest_framework import serializers\nfrom djresttoolkit.serializers.mixins import BulkCreateMixin\nfrom myapp.models import Product\n\nclass ProductSerializer(BulkCreateMixin, serializers.ModelSerializer):\n class Meta:\n model = Product\n fields = [\"id\", \"name\", \"price\"]\n\n# Single creation\nserializer = ProductSerializer(data={\"name\": \"Item1\", \"price\": 10})\nserializer.is_valid(raise_exception=True)\nproduct = serializer.save()\n\n# Bulk creation\nserializer = ProductSerializer(\n data=[\n {\"name\": \"Item2\", \"price\": 20},\n {\"name\": \"Item3\", \"price\": 30},\n ],\n many=True\n)\nserializer.is_valid(raise_exception=True)\nproducts = serializer.save()\n```\n\n#### Bulk Create Mixin Features\n\n- Works seamlessly with DRF `ModelSerializer`.\n- Automatically updates field error messages based on Django model definitions.\n- Bulk creation is optimized using `model.objects.bulk_create()` for efficiency.\n\n### 10. ModelChoiceFieldMixin \u2014 API Reference\n\n```python\nfrom djresttoolkit.models.mixins import ModelChoiceFieldMixin\n```\n\n### `ModelChoiceFieldMixin`\n\nA **Django model mixin** to retrieve **choice fields** from a model, designed to work seamlessly with Django's `TextChoices`.\n\n#### Class Attributes in Model Choice Field Mixin\n\n- `model: type[Model] | None` \u2014 The Django model class to inspect. **Must be set.**\n- `choice_fields: list[str] | None` \u2014 List of model field names that contain choices. **Must be set.**\n\n#### Model Choice Field Mixin Methods\n\n- `get_choices() -> dict[str, dict[str, str]]`\n\nRetrieve the choice fields from the model as a dictionary.\n\n- **Returns:**\n\n ```python\n {\n \"field_name\": {\n \"choice_value\": \"Choice Label\",\n ...\n },\n ...\n }\n ```\n\n- **Raises:**\n\n - `AttributeDoesNotExist` \u2014 If `model` or `choice_fields` is not set.\n - `ChoiceFieldNotFound` \u2014 If a field does not exist, has no choices, or has invalid choice format.\n\n---\n\n### Model Choice Field Mixin Example\n\n```python\nfrom django.db import models\nfrom djresttoolkit.serializers.mixins import ModelChoiceFieldMixin\n\nclass Product(models.Model):\n class Status(models.TextChoices):\n DRAFT = \"draft\", \"Draft\"\n PUBLISHED = \"published\", \"Published\"\n\n status = models.CharField(max_length=20, choices=Status.choices)\n category = models.CharField(max_length=50, choices=[\n (\"a\", \"Category A\"),\n (\"b\", \"Category B\"),\n ])\n\nclass ProductChoiceMixin(ModelChoiceFieldMixin):\n model = Product\n choice_fields = [\"status\", \"category\"]\n\nchoices = ProductChoiceMixin.get_choices()\nprint(choices)\n# Output:\n# {\n# \"status\": {\"draft\": \"Draft\", \"published\": \"Published\"},\n# \"category\": {\"a\": \"Category A\", \"b\": \"Category B\"}\n# }\n```\n\n#### Features of Model Choice Field Mixin\n\n- Safely validates that fields exist and have valid choices.\n- Returns a ready-to-use dictionary mapping values to labels.\n- Ideal for DRF serializers, forms, and admin customization.\n\nHere\u2019s a concise **docs entry** for your `ChoiceFieldsAPIView` suitable for `djresttoolkit` documentation:\n\n---\n\n### 11. ChoiceFieldsAPIView \u2014 API Reference\n\n```python\nfrom djresttoolkit.views import ChoiceFieldsAPIView\n```\n\n#### `ChoiceFieldsAPIView`\n\nA **generic DRF API view** to return all choices for specified model fields.\n\n#### Class Attributes of Choice Fields APIView\n\n- `model_class: type[Model] | None` \u2014 The Django model to inspect. **Must be set.**\n- `choice_fields: list[str] | None` \u2014 List of fields on the model with choices. **Must be set.**\n\n---\n\n#### Choice Fields APIView Methods\n\n- `get(request: Request) -> Response`\n\nFetches the choices for the configured model fields.\n\n- **Returns:**\n - `200 OK` \u2014 JSON object containing all choices:\n\n ```json\n {\n \"choices\": {\n \"status\": {\"draft\": \"Draft\", \"published\": \"Published\"},\n \"category\": {\"a\": \"Category A\", \"b\": \"Category B\"}\n }\n }\n ```\n\n - `400 Bad Request` \u2014 If any error occurs while retrieving choices.\n\n- **Raises:**\n - `AttributeDoesNotExist` \u2014 If `model_class` or `choice_fields` is not set.\n\n---\n\n### Example of Choice Fields APIView\n\n```python\nfrom django.urls import path\nfrom djresttoolkit.views import ChoiceFieldsAPIView\nfrom myapp.models import Product\n\nclass ProductChoiceAPI(ChoiceFieldsAPIView):\n model_class = Product\n choice_fields = [\"status\", \"category\"]\n\nurlpatterns = [\n path(\n \"api/v1/product-choices/\",\n ProductChoiceAPI.as_view(),\n name=\"product-choices\"\n ),\n]\n```\n\n#### Choice Fields APIView Features\n\n- Dynamically returns all choices for selected fields in a model.\n- Useful for frontend forms or API consumers that need selectable options.\n- Integrates seamlessly with `ModelChoiceFieldMixin` from `djresttoolkit`.\n\n### 12. RetrieveObjectMixin \u2014 API Reference\n\n```python\nfrom djresttoolkit.views.mixins import RetrieveObjectMixin\n```\n\n#### `RetrieveObjectMixin[T: Model]`\n\nA **generic mixin** to retrieve a single Django model instance by filters.\n\n#### Class Attributes of Retrieve Object Mixin\n\n- `queryset: QuerySet[T] | None` \u2014 The queryset used to retrieve objects. **Must be set.**\n\n#### Raises of Retrieve Object Mixin\n\n- `QuerysetNotDefinedError` \u2014 If `queryset` is not set in the class.\n\n#### Retrieve Object Mixin Methods\n\n- `get_object(**filters: Any) -> T | None`\n\nRetrieve a single model object using the provided filter criteria.\n\n- **Parameters:**\n - `**filters` \u2014 Keyword arguments to filter the queryset (e.g., `id=1`, `slug=\"abc\"`).\n\n- **Returns:**\n - Model instance matching the filters, or `None` if no match is found.\n\n#### Example of Retrieve Object Mixin\n\n```python\nfrom rest_framework.views import APIView\nfrom django.http import JsonResponse\nfrom myapp.models import Book\nfrom djresttoolkit.mixins import RetrieveObjectMixin\n\nclass BookDetailView(RetrieveObjectMixin[Book], APIView):\n queryset = Book.objects.all()\n\n def get(self, request, *args, **kwargs):\n book = self.get_object(id=kwargs[\"id\"])\n if book:\n return JsonResponse({\"title\": book.title, \"author\": book.author})\n return JsonResponse({\"detail\": \"Not found\"}, status=404)\n```\n\n#### Features of Retrieve Object Mixin\n\n- Simplifies object retrieval in class-based views or DRF views.\n- Returns `None` instead of raising `DoesNotExist`, making error handling easier.\n- Works with any Django model and queryset.\n\n### 13. build_absolute_uri \u2014 API Reference\n\n```python\nfrom djresttoolkit.urls import build_absolute_uri\n```\n\n#### build absolute uri Description\n\n- Builds a **fully qualified absolute URL** for a Django or DRF view.\n- Optionally includes **query parameters**.\n- Works with both **Django `HttpRequest`** and **DRF `Request`** objects.\n- Uses Django's `reverse()` to dynamically resolve URL names.\n\n#### build absolute uri Function Signature\n\n```python\ndef build_absolute_uri(\n request: HttpRequest | Request,\n url_name: str,\n query_params: dict[str, Any] | None = None,\n *args: Any,\n **kwargs: Any,\n) -> str:\n ...\n```\n\n---\n\n#### build absolute uri Parameters\n\n- `request` (`HttpRequest | Request`): The incoming Django or DRF request object.\n- `url_name` (`str`): Name of the URL pattern to reverse.\n- `query_params` (`dict[str, Any] | None`): Optional dictionary of query parameters to append to the URL.\n- `*args` (`Any`): Positional arguments for the URL reversal.\n- `**kwargs` (`Any`): Keyword arguments for the URL reversal.\n\n---\n\n### build absolute uri Returns\n\n- `str`: Absolute URI of the view including optional query parameters.\n\n### Example of build absolute uri\n\n```python\nfrom django.http import HttpRequest\nfrom djresttoolkit.utils import build_absolute_uri\n\ndef my_view(request: HttpRequest):\n absolute_url = build_absolute_uri(\n request,\n url_name=\"book-detail\",\n query_params={\"ref\": \"newsletter\"},\n pk=123\n )\n return HttpResponse(f\"URL: {absolute_url}\")\n```\n\n**Output Example:**\n\n```url\nhttps://example.com/api/books/123/?ref=newsletter\n```\n\n### 14. PageNumberPagination \u2014 API Reference\n\n```python\nfrom djresttoolkit.pagination import PageNumberPagination\n```\n\n#### Description of Page Number Pagination\n\n- Extends **DRF\u2019s `PageNumberPagination`** with a **cleaner metadata structure**.\n- Adds support for **dynamic page size** via the `page-size` query parameter.\n- Returns pagination metadata inside a `\"page\"` object, separate from `\"results\"`.\n\n#### Features of Page Number Pagination\n\n- Clients can control items per page using `?page-size=`.\n- Structured pagination metadata:\n\n - `current`:- current page number\n - `total`:- total number of pages\n - `size`:- number of items per page\n - `total_items`:- total number of items across all pages\n - `next`:- next page URL\n - `previous`:- previous page URL\n- Standardized API response format.\n\n### Attributes of Page Number Pagination\n\n- `page_size_query_param: str`:- Query parameter name (`\"page-size\"`).\n\n### Page Number Pagination Methods\n\n- `get_paginated_response(data: Any) -> Response`\n Returns a JSON response with both pagination metadata and results.\n\n### Example Response of Page Number Pagination\n\n```json\n{\n \"page\": {\n \"current\": 1,\n \"total\": 10,\n \"size\": 20,\n \"total_items\": 200,\n \"next\": \"http://api.example.com/items/?page=2&page-size=20\",\n \"previous\": null\n },\n \"results\": [\n { \"id\": 1, \"name\": \"Item 1\" },\n { \"id\": 2, \"name\": \"Item 2\" }\n ]\n}\n```\n\n### 15. PaginatedDataBuilder \u2014 API Reference\n\n```python\nfrom djresttoolkit.pagination import PaginatedDataBuilder\n```\n\n---\n\n#### Description of Paginated Data Builder\n\n- A **builder utility** to paginate and serialize Django QuerySets using DRF.\n- Uses the custom **`PageNumberPagination`** class for consistent pagination responses.\n- Designed for reusability inside DRF views and APIs.\n\n#### Features of Paginated Data Builder\n\n- Integrates with **DRF serializers**.\n- Handles **invalid pages** gracefully by raising `NotFound`.\n- Returns both:\n - `\"page\"`:- pagination metadata\n - `\"results\"`:- serialized data.\n- Provides **structured pagination response format**.\n\n---\n\n#### Initialization of Paginated Data Builder\n\n```python\nbuilder = PaginatedDataBuilder(\n request=request,\n serializer_class=MySerializer,\n queryset=MyModel.objects.all()\n)\n```\n\n- `request: Request`:- DRF request object.\n- `serializer_class: type[BaseSerializer]`:- DRF serializer class for the model.\n- `queryset: QuerySet`:- Django queryset to paginate.\n\n### Paginated Data Builder Methods\n\n- `get_paginated_data() -> dict[str, Any]`\n\n - Applies pagination to the queryset.\n - Serializes the paginated results.\n - Returns a dictionary with `\"page\"` and `\"results\"`.\n - Raises `NotFound` if no page data is found.\n\n### Example Response of Paginated Data Builder\n\n```json\n{\n \"page\": {\n \"current\": 2,\n \"total\": 5,\n \"size\": 20,\n \"total_items\": 100,\n \"next\": \"http://api.example.com/items/?page=3&page-size=20\",\n \"previous\": \"http://api.example.com/items/?page=1&page-size=20\"\n },\n \"results\": [\n { \"id\": 21, \"name\": \"Item 21\" },\n { \"id\": 22, \"name\": \"Item 22\" }\n ]\n}\n```\n\n### 16. Caching Mixins \u2014 API Reference\n\nThis module provides a set of DRF mixins to handle **caching for list, retrieve, and custom actions** with automatic invalidation on create, update, and destroy.\n\n#### 1\ufe0f `CacheKeyMixin`\n\n- **Purpose**: Generate unique cache keys for DRF viewset actions.\n- **Attributes**:\n - `cache_timeout: int = 300`:- default cache duration in seconds.\n- **Methods**:\n - `get_cache_timeout()`:- returns the cache timeout.\n - `get_cache_key(action_type, pk=None, action_name=None)`:- returns a cache key string based on action type:**\n - `list` or `custom-list`:- hash of query parameters.\n - `retrieve` or `custom-detail`:- uses primary key (`pk`).\n\n#### 2\ufe0f `CacheOpsMixin`\n\n- **Purpose**: Get, set, and invalidate cache.\n- **Methods**:\n - `get_or_set_cache(cache_key, data_fn, timeout=None)`:- fetch from cache or compute and set.\n - `invalidate_cache(pk=None, custom_actions=None)`:- delete cached items:\n - Deletes retrieve/detail caches for a `pk`.\n - Deletes list caches (supports `delete_pattern` if available).\n\n#### 3\ufe0f `CacheActionMixin`\n\n- **Purpose**: Decorator for caching custom DRF `@action` methods.\n- **Methods**:\n - `cache_action(detail=False, action_name=None)`:- returns a decorator that caches action results automatically.\n - Works for:\n - `detail=False`:- custom-list action cache.\n - `detail=True`:- custom-detail action cache.\n\n#### 4\ufe0f `CacheListRetrieveMixin`\n\n- **Purpose**: Caches DRF `list()` and `retrieve()` responses.\n- **Methods**:\n - `list(request, *args, **kwargs)`:- caches list responses.\n - `retrieve(request, *args, **kwargs)`:- caches detail responses.\n - `_get_list_data(request)`:- internal method to fetch paginated list data.\n - `_get_detail_data()`:- internal method to fetch a single object.\n\n#### 5\ufe0f `CacheInvalidateMixin`\n\n- **Purpose**: Automatically invalidates caches on write operations.\n- **Methods**:\n - `create(request, *args, **kwargs)`:- invalidates list caches.\n - `update(request, *args, **kwargs)`:- invalidates detail caches for `pk`.\n - `destroy(request, *args, **kwargs)`:- invalidates detail caches for `pk`.\n\n#### Example of Caching Mixins\n\n```python\nfrom rest_framework.viewsets import ModelViewSet\nfrom myapp.models import Book\nfrom myapp.serializers import BookSerializer\nfrom djresttoolkit.cache.mixins import CacheInvalidateMixin, CacheActionMixin\n\nclass BookViewSet(CacheInvalidateMixin, ModelViewSet):\n queryset = Book.objects.all()\n serializer_class = BookSerializer\n basename = \"book\"\n\n @CacheActionMixin.cache_action(detail=False)\n def popular(self, request):\n data = Book.objects.filter(is_popular=True)\n serializer = self.get_serializer(data, many=True)\n return Response(serializer.data)\n```\n\n- Automatically caches `list`, `retrieve`, and `popular` actions.\n- Invalidates caches when books are created, updated, or deleted.\n- Supports custom cache keys per action.\n\n## \ud83d\udee0\ufe0f Planned Features\n\n- Add more utils\n\n## \ud83e\udd1d Contributing\n\nContributions are welcome! Please open an issue or PR for any improvements.\n\n## \ud83d\udcdc License\n\nMIT License \u2014 See [LICENSE](LICENSE).\n\n## \ud83d\udc64 Author\n\nFor questions or assistance, contact **Shailesh** at [shaileshpandit141@gmail.com](mailto:shaileshpandit141@gmail.com).\n",
"bugtrack_url": null,
"license": "# MIT License Copyright (c) 2025 Shailesh Pandit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"summary": "A collection of Django and DRF utilities to simplify API development.",
"version": "0.17.3",
"project_urls": {
"Documentation": "https://shaileshpandit141.github.io/djresttoolkit",
"Homepage": "https://github.com/shaileshpandit141/djresttoolkit",
"Issues": "https://github.com/shaileshpandit141/djresttoolkit/issues",
"License": "https://github.com/shaileshpandit141/djresttoolkit/blob/main/LICENSE",
"Source": "https://github.com/shaileshpandit141/djresttoolkit"
},
"split_keywords": [
"api-development",
" django",
" django-authentication",
" django-email",
" django-helpers",
" django-mixins",
" django-pagination",
" django-rest",
" django-rest-framework-utilities",
" django-rest-utilities",
" django-serializers",
" django-shortcuts",
" django-utilities",
" djangorestframework",
" drf",
" python-package",
" rest-api"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "3e4a6dbaab4a75b36da529413fceddcf3d0c29b6f2cda6883fa37023dd2396a4",
"md5": "0e6d11b870280e884ed5fa30e20cbcb5",
"sha256": "b682b26e4470451b39c8a0befe8c42a28b3f2f408ee36283584c3349910d9ebd"
},
"downloads": -1,
"filename": "djresttoolkit-0.17.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0e6d11b870280e884ed5fa30e20cbcb5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 43118,
"upload_time": "2025-08-24T07:25:05",
"upload_time_iso_8601": "2025-08-24T07:25:05.501113Z",
"url": "https://files.pythonhosted.org/packages/3e/4a/6dbaab4a75b36da529413fceddcf3d0c29b6f2cda6883fa37023dd2396a4/djresttoolkit-0.17.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "eb5146b456b751474c94090de949763b7e0ddbd8df934358b9a541617da51dd8",
"md5": "a268ac1f72aaf88ea536d432367b3a89",
"sha256": "2623b59d75c51979b72555980c10aff815045321e9d6cc1598acffcbc15e8f61"
},
"downloads": -1,
"filename": "djresttoolkit-0.17.3.tar.gz",
"has_sig": false,
"md5_digest": "a268ac1f72aaf88ea536d432367b3a89",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 1100819,
"upload_time": "2025-08-24T07:25:22",
"upload_time_iso_8601": "2025-08-24T07:25:22.625408Z",
"url": "https://files.pythonhosted.org/packages/eb/51/46b456b751474c94090de949763b7e0ddbd8df934358b9a541617da51dd8/djresttoolkit-0.17.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-24 07:25:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "shaileshpandit141",
"github_project": "djresttoolkit",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "djresttoolkit"
}