55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
from typing import Type, Optional, Self, override
|
|
|
|
from rest_framework.viewsets import ViewSetMixin # type: ignore
|
|
from rest_framework.routers import DefaultRouter # type: ignore
|
|
|
|
|
|
class TypedRouter(DefaultRouter):
|
|
"""
|
|
A subclass of DRF's `rest_framework.routers.DefaultRouter` that adds proper static
|
|
type annotations to certain methods — particularly the `register` method.
|
|
|
|
This resolves issues with static analysis tools such as MyPy and Pyright,
|
|
which normally raise warnings or require `# type: ignore` comments due to the
|
|
original method's lack of strict typing.
|
|
|
|
Benefits:
|
|
- Eliminates the need to use `# type: ignore` when calling `.register(...)`
|
|
- Improves type safety by enforcing that only subclasses of `ViewSetMixin` are passed
|
|
- Enhances developer experience (DX) in statically typed projects
|
|
- Promotes DRY principles by reducing repetitive ignores across the codebase
|
|
|
|
This class does not modify any runtime behavior of `DefaultRouter`. It is purely a DX
|
|
and tooling improvement for typed Python projects using Django REST Framework (DRF).
|
|
|
|
Example:
|
|
from my_project.routers import TypedRouter
|
|
from my_app.api import UserViewSet
|
|
|
|
router = TypedRouter()
|
|
router.register("users", UserViewSet, basename="user")
|
|
"""
|
|
|
|
@override
|
|
def register( # type: ignore
|
|
self,
|
|
prefix: str,
|
|
viewset: Type[ViewSetMixin],
|
|
basename: Optional[str] = None,
|
|
**kwargs: object
|
|
) -> Self:
|
|
"""
|
|
Registers a viewset with a given URL prefix and optional basename, with proper type hints
|
|
to improve static analysis (e.g., with MyPy or Pyright) when using DRF's DefaultRouter.
|
|
|
|
This method overrides `DefaultRouter.register()` to annotate the expected `viewset` type
|
|
as a subclass of `ViewSetMixin`, which reflects how DRF expects viewsets to behave.
|
|
|
|
Useful for eliminating `# type: ignore` comments and improving autocompletion.
|
|
|
|
See also:
|
|
- DRF Router documentation: https://www.django-rest-framework.org/api-guide/routers/
|
|
"""
|
|
super().register(prefix=prefix, viewset=viewset, basename=basename, **kwargs) # type: ignore
|
|
return self
|