Skip to content

Commit 0b2a417

Browse files
authored
Make some mixin methods generic (#131)
1 parent 1761be9 commit 0b2a417

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

rest_framework-stubs/mixins.pyi

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
from typing import Any, Dict
1+
from typing import Any, Dict, TypeVar
22

33
from django.db.models import Model
4+
5+
from rest_framework.generics import UsesQuerySet
46
from rest_framework.request import Request
57
from rest_framework.response import Response
68
from rest_framework.serializers import BaseSerializer
79

10+
_MT = TypeVar("_MT", bound=Model)
11+
812
class CreateModelMixin:
913
def create(self, request: Request, *args: Any, **kwargs: Any) -> Response: ...
10-
def perform_create(self, serializer: BaseSerializer) -> None: ...
14+
def perform_create(self: UsesQuerySet[_MT], serializer: BaseSerializer[_MT]) -> None: ...
1115
def get_success_headers(self, data: Any) -> Dict[str, str]: ...
1216

1317
class ListModelMixin:
@@ -18,9 +22,9 @@ class RetrieveModelMixin:
1822

1923
class UpdateModelMixin:
2024
def update(self, request: Request, *args: Any, **kwargs: Any) -> Response: ...
21-
def perform_update(self, serializer: BaseSerializer) -> None: ...
25+
def perform_update(self: UsesQuerySet[_MT], serializer: BaseSerializer[_MT]) -> None: ...
2226
def partial_update(self, request: Request, *args: Any, **kwargs: Any) -> Response: ...
2327

2428
class DestroyModelMixin:
2529
def destroy(self, request: Request, *args: Any, **kwargs: Any) -> Response: ...
26-
def perform_destroy(self, instance: Model) -> None: ...
30+
def perform_destroy(self: UsesQuerySet[_MT], instance: _MT) -> None: ...

tests/typecheck/test_mixins.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
- case: test_create
2+
main: |
3+
from rest_framework.mixins import CreateModelMixin
4+
from rest_framework.generics import GenericAPIView
5+
from rest_framework.serializers import BaseSerializer, ModelSerializer
6+
from django.db.models import Model
7+
8+
class MyModel(Model):
9+
pass
10+
11+
class MyView(GenericAPIView, CreateModelMixin):
12+
def perform_create(self, serializer: BaseSerializer[MyModel]) -> None: ...
13+
14+
- case: test_perform_update
15+
main: |
16+
from rest_framework.mixins import UpdateModelMixin
17+
from rest_framework.generics import GenericAPIView
18+
from rest_framework.serializers import BaseSerializer
19+
from django.db.models import Model
20+
21+
class MyModel(Model):
22+
pass
23+
24+
class MyView(GenericAPIView, UpdateModelMixin):
25+
def perform_update(self, serializer: BaseSerializer[MyModel]) -> None: ...
26+
27+
- case: test_perform_destroy
28+
main: |
29+
from rest_framework.mixins import DestroyModelMixin
30+
from rest_framework.generics import GenericAPIView
31+
from rest_framework.serializers import BaseSerializer
32+
from django.db.models import Model
33+
34+
class MyModel(Model):
35+
pass
36+
37+
class MyView(GenericAPIView, DestroyModelMixin):
38+
def perform_destroy(self, instance: MyModel) -> None: ...

tests/typecheck/test_views.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,16 @@
66
def filter_queryset(self, queryset):
77
reveal_type(self.request) # N: Revealed type is 'rest_framework.request.Request'
88
return queryset
9+
10+
- case: test_destroy_api_view
11+
main: |
12+
from rest_framework import generics
13+
from django.db.models import Model
14+
15+
class MyModel(Model):
16+
pass
17+
18+
class MyView(generics.DestroyAPIView):
19+
queryset = MyModel.objects.all()
20+
21+
def perform_destroy(self, instance: MyModel) -> None: ...

0 commit comments

Comments
 (0)