with custom AuthenticationForm get error when trying login with a non-existent account but when use existent account error dont raise
File "C:\python\CTFp\.venv\Lib\site-packages\django\utils\functional.py", line 253, in inner
return func(_wrapped, *args)
^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'AnonymousUser' object has no attribute '_meta'
forms.py
class AuthenticationForm(BaseAuthenticationForm):
def clean(self):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
ogg = User.objects.filter(Q(email=username) or Q(username=username)).first()
if ogg is not None and password:
self.user_cache = authenticate(
self.request, username=ogg.username, password=password
)
if self.user_cache is None:
raise self.get_invalid_login_error()
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
urls.py
urlpatterns = [path('signin', views.LoginView.as_view(authentication_form=forms.AuthenticationForm),
{'template_name': 'users/signin.html'},
name='signin'),]
models.py
class User(AbstractUser):
challenges = models.ManyToManyField(Challenge)
tried to change auth form to base AuthenticationForm and error dont raises.
I think you are trying to fix the problem at the wrong location: the form should not be responsible on how to authenticate, that should the authentication backend do. We can write a custom authentication backend [Django-doc] to work with a username or an email:
# app_name/authentication.py
from django.contrib.auth.backends import BaseBackend
from django.db.models import Q
class UsernameEmailAuthenticationBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
try:
user = User.objects.get(Q(email=username) | Q(username=username))
except User.DoesNotExist:
return None
if user.check_password(password):
return user
return None
and add this to the AUTHENTICATION_BACKENDS
setting [Django-doc]:
# settings.py
# …
AUTHENTICATION_BACKENDS = ['app_name.authentication.UsernameEmailAuthenticationBackend']
Although probably not the most important part, it means it will fetch the user once, whereas by trying to find the username in the form would trigger a second query.