# User vs AbstractBaseUser

**URL:** <https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025>\
**Category:** Getting Started\
**Created:** [October 28, 2024, 8:24pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025 "2024-10-28T20:24:00Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![jonmooser](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jonmooser/32/24846_2.png) [@jonmooser](https://forum.djangoproject.com/u/jonmooser)\
**Post date:** [October 28, 2024, 8:24pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/1 "2024-10-28T20:24:00Z")

</div>

Seems like this would be answered somewhere, but I can’t find it. Please feel free to redirect me to another post if it has.

When I access `request.user` the type is `AbstractBaseUser`  
This mean that calls like `user.username` cause the typechecker to report an error.

The workaround I have found is something like

```auto
user = request.user
assert isinstance(user, User)
username = user.username

```

Is this best practice, or is there a preferable way?

---

<div class="post-metadata">

**Author:** ![white-seolpyo](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/white-seolpyo/32/22386_2.png) [@white-seolpyo](https://forum.djangoproject.com/u/white-seolpyo)\
**Post date:** [October 29, 2024, 12:14am UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/2 "2024-10-29T00:14:23Z")

</div>

if just get username, check user is login or not.

```auto
username = request.user.username if request.user.is_authenticated else None

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 29, 2024, 12:15am UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/3 "2024-10-29T00:15:55Z")

</div>

Welcome @jonmooser !

What specifically are you looking at that is making you think that `request.user` is of type `AbstractBaseUser`? (Are you using a custom user model?)

The code throughout the authentication middleware always assigns an instance of `UserModel` to `user`. (See `ModelBackend.authenticate`)

On my system, print(type(request.user)) gives `<class 'django.utils.functional.SimpleLazyObject'>` and `print(request.user. __class__ )` gives either `<class 'django.contrib.auth.models.AnonymousUser'>` or `<class 'django.contrib.auth.models.User'>`, depending upon whether the user is authenticated or not.

---

<div class="post-metadata">

**Author:** ![jonmooser](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jonmooser/32/24846_2.png) [@jonmooser](https://forum.djangoproject.com/u/jonmooser)\
**Post date:** [October 29, 2024, 4:50am UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/4 "2024-10-29T04:50:01Z")

</div>

The specific error in VSCode (using pylance for type checking) reads:

```auto
Cannot access attribute "username" for class "AbstractBaseUser"
  Attribute "username" is unknown Pylance (reportAttributeAccessIssue)

```

It looks like it’s coming from the django stubs in pylance, `request.pyi`:

```auto
class HttpRequest:
    GET: QueryDict = ...
    POST: QueryDict = ...
    COOKIES: dict[str, str] = ...
    META: dict[str, Any] = ...

    # ...
    # ...

    # Attributes added by commonly-used middleware
    user: AbstractBaseUser | AnonymousUser
    site: Site
    session: SessionBase

```

So the runtime returns the correct type, but the language server thinks it’s AbstractBaseUser.  
Have others run into this? Do you just ignore it?

I guess it’s not technically a bug because Pylance doesn’t know what specific type of `user` the authentication middleware will set.

---

<div class="post-metadata">

**Author:** ![white-seolpyo](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/white-seolpyo/32/22386_2.png) [@white-seolpyo](https://forum.djangoproject.com/u/white-seolpyo)\
**Post date:** [October 29, 2024, 8:19am UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/5 "2024-10-29T08:19:10Z")

</div>

AbstractBaseUser is a base model for creating a user model, and is a model that cannot be used directly.

What is actually used is the User model using AbstractBaseUser as the base.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 29, 2024, 1:00pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/6 "2024-10-29T13:00:18Z")

</div>

> [@jonmooser](#):
>
> Have others run into this? Do you just ignore it?

I have not encountered this. (Nor would I.)

`<opinion>`  
I don’t use any typing in my code. I find it adds more visual clutter to the code than the value it provides. As a result, I don’t use any of the “typing-related” tools in my work environment.  
(That Python does not require explicit typing, and provides “duck typing” as a fundamental principle, is one of the reasons I moved to using Python as my primary language of choice 20+ years ago. I have no desire to see Python move anywhere in the direction of Java.)  
`</opinion>`

> [@jonmooser](#):
>
> I guess it’s not technically a bug because Pylance doesn’t know what specific type of `user` the authentication middleware will set.

This is correct - and shows one of the reasons _why_ I’m not a fan of typing in Python.

Technically, not only can the user model be changed (using the `AUTH_USER_MODEL` setting), but this user model does not need to have any relationship with `AbstractBaseUser`. Also, if you have multiple authentication backends in your project, `request.user` can be _different_ types based upon the backend.

---

<div class="post-metadata">

**Author:** ![massover](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/massover/32/1792_2.png) [@massover](https://forum.djangoproject.com/u/massover)\
**Post date:** [October 29, 2024, 2:55pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/7 "2024-10-29T14:55:55Z")

</div>

Have you looked at using [django-stubs](https://github.com/typeddjango/django-stubs?tab=readme-ov-file#how-can-i-create-a-httprequest-thats-guaranteed-to-have-an-authenticated-user)? It has a suggestion for how to use typed attributes on HttpRequest

---

<div class="post-metadata">

**Author:** ![jonmooser](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jonmooser/32/24846_2.png) [@jonmooser](https://forum.djangoproject.com/u/jonmooser)\
**Post date:** [October 29, 2024, 5:06pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/8 "2024-10-29T17:06:57Z")

</div>

Interesting `<opinion>`! Thanks for sharing it.

This clearly gets into a much bigger philosophical debate than one little aspect of Django. I think (think) you may be in the minority, and that most python programmers are using pylance or mypy or something for static type checking.

But I could be wrong and your preference of relying on duck typing has certainly given me pause for thought.

All of that said, going back to my original question, would you say my idea of using an `assert` statement makes sense then?

```auto
user = request.user
if user.is_authenticated:
    assert isinstance(user, User)
    ...
    name = user.username

```

My thinking is that if for some bizarre reason `user` is _not_ an instance of `User`, I want it to fail hard and early, before I’ve had a chance to do anything with that object. Thoughts?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 29, 2024, 5:35pm UTC](https://forum.djangoproject.com/t/user-vs-abstractbaseuser/36025/9 "2024-10-29T17:35:06Z")

</div>

> [@jonmooser](#):
>
> I think (think) you may be in the minority,

I probably am, and that’s ok. I hold many opinions that probably put me in the minority in a number of different areas. Some of that is due to my background, and some due to the nature of most of the work I do. I learned a long time ago that I come to Django with a very different perspective.

> [@jonmooser](#):
>
> My thinking is that … Thoughts?

Actually, I think I kind of addressed this in my previous response:

> [@KenWhitesell](#):
>
> Technically, not only can the user model be changed (using the `AUTH_USER_MODEL` setting), but this user model does not need to have any relationship with `AbstractBaseUser`. Also, if you have multiple authentication backends in your project, `request.user` can be _different_ types based upon the backend.

The entity, `request.user`, is whatever your authentication backend returns for the user being authenticated.

Applying that to this case:

> [@jonmooser](#):
>
> ```auto
> assert isinstance(user, User)
> ...
> name = user.username
> 
> ```

The assert enforces a requirement that may not be necessarily correct within the context of this code.

If `user` is not an instance of `User`, you do get an error. But what if you want to deploy this in a project using a custom authentication backend that doesn’t use the standard `django.auth.User` model?

Or, what if it is deployed in a project that uses a custom `User` model without a `username` attribute, but names it `User`? In _that_ case, it will pass the assert, but throw an error at `name = user.username` anyway.

But that line `name = user.username` _will_ work if `user` is something like `MyCustomUser`, if that class provides a `username` attribute or property.

> [@jonmooser](#):
>
> My thinking is that if for some bizarre reason `user` is _not_ an instance of `User`,

So this brings me back around to a more basic question.

Do you **really** care whether `request.user` is an instance of a class named `User`? If so, why? (And if so, I would suggest that you’re better off making this test in middleware rather than scattered around multiple views.)

Or is your concern only that `request.user` provides the attributes and properties that the rest of this view requires?

Whether or not _this_ question makes a difference depends upon the scope of usage of your code.

If this code is specific to one particular project in a given environment, then it probably doesn’t matter.

But if you’re building a library of code - even if it’s for your own personal use and not going to be shared outside your organization - then these are types of questions you would want to consider.
