Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request.user does not use custom User model #515

Open
ollejernstrom opened this issue Dec 4, 2023 · 3 comments
Open

request.user does not use custom User model #515

ollejernstrom opened this issue Dec 4, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@ollejernstrom
Copy link

ollejernstrom commented Dec 4, 2023

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 of AbstractBaseUser | AnonymousUser

System information

  • OS: MAC
  • python version: 3.11
  • django version: 4.2
  • mypy version: 1.7.1
  • django-stubs version: (latest)
@ollejernstrom ollejernstrom added the bug Something isn't working label Dec 4, 2023
@ollejernstrom ollejernstrom changed the title Response.user does not use custom Auth model request.user does not use custom Auth model Dec 5, 2023
@ollejernstrom
Copy link
Author

ollejernstrom commented Dec 5, 2023

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

@intgr
Copy link
Contributor

intgr commented Dec 8, 2023

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.

@intgr intgr changed the title request.user does not use custom Auth model request.user does not use custom User model Dec 8, 2023
@ysmolski
Copy link

ysmolski commented Feb 5, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

3 participants