0π
You could always refetch the user from the database using select_related
and prefetch_related
. If select_related
and prefetch_related
save a lot of queries, then it will be worth the extra query to fetch the user.
def profile(request):
user = User.objects.select_related(
...
).prefetch_related(
...
).get(pk=request.user.pk)
Note that depending on the view, prefetch_related
might not be very useful in this case. It causes one extra query per model, so itβs most useful when you are fetching the related objects for an entire queryset, not a single object.
27π
Sorry for this necroposting, but this theme is so important and really simple answer exists, just create a custom manager for your user model and override the get
method with select_related
like this:
from django.contrib.auth.models import AbstractUser, UserManager
class CustomUserManager(UserManager):
def get(self, *args, **kwargs):
return super().select_related('<put fields that you want>').get(*args, **kwargs)
class CustomUser(AbstractUser):
...
objects = CustomUserManager()
Now, whenever Django will retrieve user instance for request.user
, it will be using this manager. Also all your CustomUser.objects.get()
queries will select specified related fields too.
- Django: model has two ManyToMany relations through intermediate model
- How to clear all session variables without getting logged out
- How to cancel a delete in django signal
- Django: HTTPS for just login page?
2π
A more granual way could be using a custom authentication backend. By using this approach one will be able to use UserModel.objects.get without the drawback of making unnecessary joins(.select_related()) or DB lookups(.prefetch_related()) while using this manager in other segments of code.
# auth_backends.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
UserModel = get_user_model()
class RelatedModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
try:
user = UserModel._default_manager.select_related(
... # Do your magic here
).prefetch_related(
... # Do your magic here
)
get(
**{UserModel.USERNAME_FIELD: username}
)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel._default_manager.select_related(
... # Do your magic here
).prefetch_related(
... # Do your magic here
).get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
Now we need to add new backend into settings file, read more about custom auth backends here.
# settings.py
...
AUTHENTICATION_BACKENDS = ['myproject.auth_backends.RelatedModelBackend']
...
- How to display "x days ago" type time using Humanize in Django template?
- Django ORM: window function with subsequent filtering
- What does request.GET.get mean?