djangorestframework-stubs
djangorestframework-stubs copied to clipboard
request.user does not use custom User model
Bug report
What's wrong
These are from the Request object in the stubbs.
def user(self) -> AbstractBaseUser | AnonymousUser: ...
@user.setter
def user(self, value: AbstractBaseUser | AnonymousUser) -> None: ...
However i have a different auth model defined in my settings.py
called CustomUser
AUTH_USER_MODEL = "base.CustomUser"
Is there a way to get this typing correct.
Use case error:
user = self.request.user
if user.can_manage():
return queryset
products/views.py:145: error: Item "AnonymousUser" of "AbstractBaseUser | AnonymousUser" has no attribute "can_manage" [union-attr]
Furthermore, if the permission classes dont allow "AnonymousUser" can we type narrow that somehow? (Like in django-stubs
How can I create a HttpRequest that's guaranteed to have an authenticated user?
How is that should be
It should be narrowed to just my CustomUser
TL;DR:
- How can i only see
CustomUser
instead ofAbstractBaseUser | AnonymousUser
System information
- OS: MAC
-
python
version: 3.11 -
django
version: 4.2 -
mypy
version: 1.7.1 -
django-stubs
version: (latest)
I found a solution, if anyone has a better, please tell me:
from rest_framework.request import Request, wrap_attributeerrors
from django.db.models import Model
from django.http import HttpRequest
from rest_framework.generics import (
CreateAPIView,
DestroyAPIView,
GenericAPIView,
ListAPIView,
ListCreateAPIView,
RetrieveAPIView,
RetrieveDestroyAPIView,
RetrieveUpdateAPIView,
RetrieveUpdateDestroyAPIView,
UpdateAPIView,
)
from rest_framework.request import Request
from rest_framework.views import APIView
from base.db.models import CustomUser # my user model
class AuthenticatedApiRequest(Request):
@property
def user(self) -> CustomUser:
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
@user.setter
def user(self, value: CustomUser) -> None:
self._user = value
self._request.user = value
T = TypeVar('T', bound=Model)
class AuthedViewMixin(APIView):
"""Mixin that types user as authenticated"""
request: AuthenticatedApiRequest
permission_classes = [IsAuthenticated]
@override
def initialize_request(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Request:
"""Override to use AuthenticatedApiRequest"""
return AuthenticatedApiRequest(request, *args, **kwargs)
class ListCreateAuthedAPIView(AuthedViewMixin, ListCreateAPIView[T]):
pass
...
Using the ListCreateAuthedAPIView
now types the user correctly
Thanks!
django-stubs
also has a similar common issue and they suggest something analogous: https://github.com/typeddjango/django-stubs#how-can-i-create-a-httprequest-thats-guaranteed-to-have-an-authenticated-user
Personally, I've opted to just use assert isinstance(request.user, CustomUser)
in functions where I need to access the user.
I wonder if it is possible to solve it at all. All I can think of are workarounds. Trying to inherit from Request
when there are imported stubs for DRF won't work becuause it produces override type error.
The only crutch we are left with is an assertion.