From 11fca8dc8e01b557d151af6136a240255b7601e8 Mon Sep 17 00:00:00 2001 From: Jonathan Sundqvist Date: Sun, 11 Jul 2021 21:58:06 +0200 Subject: [PATCH] Introduce our own ModelBackend to reduce queries --- account/auth_backends.py | 26 +++++++++++++++++++++++--- account/models.py | 7 +++---- docs/installation.rst | 7 +++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/account/auth_backends.py b/account/auth_backends.py index d3777edb..a1d759d3 100644 --- a/account/auth_backends.py +++ b/account/auth_backends.py @@ -6,13 +6,31 @@ from account.utils import get_user_lookup_kwargs -class UsernameAuthenticationBackend(ModelBackend): +User = get_user_model() + + +class AccountModelBackend(ModelBackend): + """ + This authentication backend ensures that the account is always selected + on any query with the user, so we don't issue extra unnecessary queries + """ + + def get_user(self, user_id): + """Get the user and select account at the same time""" + user = User._default_manager.filter(pk=user_id).select_related('account').first() + if not user: + return None + return user if self.user_can_authenticate(user) else None + + +class UsernameAuthenticationBackend(AccountModelBackend): + """Username authentication""" def authenticate(self, request, username=None, password=None, **kwargs): + """Authenticate the user based on user""" if username is None or password is None: return None - User = get_user_model() try: lookup_kwargs = get_user_lookup_kwargs({ "{username}__iexact": username @@ -25,9 +43,11 @@ def authenticate(self, request, username=None, password=None, **kwargs): return user -class EmailAuthenticationBackend(ModelBackend): +class EmailAuthenticationBackend(AccountModelBackend): + """Email authentication""" def authenticate(self, request, username=None, password=None, **kwargs): + """Authenticate the user based email""" qs = EmailAddress.objects.filter(Q(primary=True) | Q(verified=True)) if username is None or password is None: diff --git a/account/models.py b/account/models.py index 7d479a11..01eee91f 100644 --- a/account/models.py +++ b/account/models.py @@ -38,10 +38,9 @@ class Account(models.Model): def for_request(cls, request): user = getattr(request, "user", None) if user and user.is_authenticated: - try: - return Account._default_manager.get(user=user) - except Account.DoesNotExist: - pass + account = user.account + if account: + return account return AnonymousAccount(request) @classmethod diff --git a/docs/installation.rst b/docs/installation.rst index 2f83a991..32ff4afd 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -67,6 +67,13 @@ Optionally include ``account.middleware.ExpiredPasswordMiddleware`` in ... ] +Set the authentication backends to the following:: + + AUTHENTICATION_BACKENDS = [ + 'account.auth_backends.AccountModelBackend', + 'django.contrib.auth.backends.ModelBackend' + ] + Once everything is in place make sure you run ``migrate`` to modify the database with the ``account`` app models.