I am trying to implement a custom user model. Whenever I try to log in for a user (created using the registration form), it returns no user.
but if I create a user using the admin panel then the login function works perfectly.
I think the problem is with password hashing. Tried some solve from here and there but seems like I can't find what I am looking for.
The problem I am having :
email: yeamin21#outlook.com
pass: 1234 works (created using admin panel)
but, email: yeamin21#outlook.com
pass: hashed(1234) does not (created using the registration form)
models.py
from django.contrib.auth.base_user import AbstractBaseUser
from django.db import models
class User(AbstractBaseUser):
username = models.CharField(max_length=30,unique=True)
email = models.EmailField(verbose_name='Email',unique=True)
name = models.CharField(max_length=100)
is_active = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
is_restaurant = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
def __str__(self):
return self.name
class Restaurant(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
location = models.CharField(max_length=200)
def __str__(self):
return self.user.email
forms.py
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from Customer.models import User, Restaurant
class RestaurantSignUpForm(UserCreationForm):
class Meta(UserCreationForm):
model = User
fields = ['email','name','username']
#transaction.atomic
def save(self, commit=True):
user = super().save(commit=False)
user.is_restaurant=True
user.is_active=True
user.save()
restaurant = Restaurant.objects.create(user=user)
restaurant.save()
return user
backend.py
from django.contrib.auth.backends import BaseBackend, ModelBackend
from Customer.models import User
class CustomBackend(ModelBackend):
def authenticate(self,email=None,password=None):
try:
user=User.objects.get(email=email)
print('active')
if user.check_password(password) is True:
return user
except User.DoesNotExist:
return None
return User.objects.get(email=User.email)
def get_user(self, email):
try:
return User.objects.get(email)
except User.DoesNotExist:
return None
views.py
from django.contrib.auth import login, authenticate
from django.http import HttpResponse
from django.shortcuts import render
from django.views import generic
from Customer.forms import RestaurantSignUpForm
from Customer.models import User
def login_page(request):
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
user = authenticate(request, email=email, password=password)
print(user)
if user is not None:
login(request, user)
return HttpResponse("Logged in")
else:
print(user)
context = {}
return render(request, 'login.html', context)
The problem is fixed
thanks to this https://stackoverflow.com/a/48971226/10602634
def authenticate(self, request, email=None, password=None):
try:
user= User.objects.get(email=email)
if check_password(password, user.password):
return user
except User.DoesNotExist:
return None
Related
I have two different forms in my register page as the one to one relationship in one of the model will show a drop down box therefore I am using the second models field where the user will have to input the field.
How would I make it so when the forms are valid, the 'SNI' will save to the first form and not the second.
Model
from asyncio import FastChildWatcher
import email
from pyexpat import model
from xxlimited import Null
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class userCouncil(BaseUserManager):
def create_user(self, userID, password=None):
if not email:
raise ValueError("Email is required")
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, userID, password):
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class sni(models.Model):
SNI = models.CharField(max_length=256, primary_key=True)
Used = models.IntegerField(null=True, blank=True)
password = None
USERNAME_FIELD = 'SNI'
def __str__(self):
return self.SNI
class Account(AbstractBaseUser):
userID = models.EmailField(primary_key= True ,max_length=256, unique=True)
name = models.CharField(max_length=100)
dateOfBirth = models.DateField(max_length=8, null=True)
homeAddress = models.CharField(max_length=100, null=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
sni = models.OneToOneField(sni, on_delete=models.CASCADE, null=True, blank=True)
USERNAME_FIELD = 'userID'
objects = userCouncil()
def __str__(self):
return self.userID
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Forms
import email
from pprint import isreadable
from pyexpat import model
from statistics import mode
from tabnanny import check
from xxlimited import Null
from attr import field
from django.forms import ModelForm, forms, widgets
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from matplotlib import use
from matplotlib.style import context
from .models import Account, sni
class createUserForm(UserCreationForm):
class Meta:
model = Account
fields = ['userID','name','dateOfBirth','homeAddress','password1','password2', 'sni']
def clean_userID(self):
userID = self.cleaned_data['userID'].lower()
u = self.cleaned_data['userID']
check_existing = Account.objects.filter(userID=userID).exists()
if check_existing:
raise forms.ValidationError("The following userID already exists: " + u)
else:
return userID
class SNIForm(UserCreationForm):
class Meta:
model = sni
fields = ['SNI', 'Used']
class AccountAuthenticationForm(forms.ModelForm):
password = forms.CharField(label = "password", widget = forms.PasswordInput)
class Meta:
model = Account
fields = ('userID', 'password')
Views
from django.shortcuts import redirect, render
from django.http import HttpResponse
from matplotlib import use
from matplotlib.pyplot import get
from matplotlib.style import context
from werkzeug import Request
from .models import *
from django.contrib.auth.hashers import make_password, check_password
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
from django.contrib.auth import authenticate
from django.contrib.auth import login as dj_login
from django.forms import ModelForm, forms
from django.contrib.auth.decorators import login_required
from .forms import AccountAuthenticationForm, SNIForm, createUserForm
def login(request):
context = {}
if request.method == 'POST':
username = request.POST.get('username').lower()
password = request.POST.get('password')
user = authenticate(request, userID = username, password = password)
form = AccountAuthenticationForm(request.GET)
if user is not None:
dj_login(request, user)
return redirect('dashboardPage')
else:
messages.info(request, "userID or password is incorrect")
return render(request, 'base.html', context)
def registerPage(request):
form = createUserForm()
form2 = SNIForm()
if request.method == 'POST':
form = createUserForm(request.POST)
form2 = SNIForm(request.POST)
if form.is_valid() and form2.is_valid:
print(form2['SNI'].value)
form.save()
form2.save()
userID = form.cleaned_data.get('userID')
messages.success(request, "Account created for: " + userID)
return redirect('loginPage')
context = {'form' : form, 'form2' : form2}
return render(request, 'register.html', context)
#login_required(login_url='loginPage')
def dashboardPage(request):
context = {}
return render(request, 'dashboard.html', context)
In views please refer to the registerPage function. Thank you
What the first form can take is Sni_id.
There is no sni_id without first saving an sni instance.
What you can do is...
Save both forms
f=form.save()
f2=form2.save()
f2.instance.user = f.instance.id
UPDATE:
if form2.is_valid():
sni = form2.data["sni"]
used = form2.data["used"]
if SNI.objects.filter(sni=sni, used=used).exists()
f=form.save()
I am able to create a New User using the "register" endpoint. I can the user being created on the admin page as well. When I try to get an access token for the newly created user I get the error "detail": "No active account found with the given credentials". I am correctly passing the valid credentials so I don't know what the problem might be. Here I have demonstrated the same.
Here goes the code:
serializers.py
from rest_framework import serializers
from .models import CustomUser
from django.contrib.auth.hashers import make_password
class RegisterUserSerializers(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('email', 'password')
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
def validate_password(self, value: str) -> str:
"""
Hash value passed by user.
:param value: password of a user
:return: a hashed version of the password
"""
return make_password(value)
views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from .serializers import RegisterUserSerializers
from rest_framework_simplejwt.tokens import RefreshToken
class CustomUserCreate(APIView):
permission_classes = [AllowAny]
def post(self, request):
reg_serial = RegisterUserSerializers(data=request.data)
if reg_serial.is_valid():
newUser = reg_serial.save()
if newUser:
context = {
"message": f"User created {newUser}"
}
return Response(context, status=status.HTTP_201_CREATED)
return Response(reg_serial.errors, status=status.HTTP_400_BAD_REQUEST)
class BlacklistTokenView(APIView):
permission_classes = [AllowAny]
def post(self, request):
try:
refresh_token = request.data["refresh_token"]
token = RefreshToken(refresh_token)
token.blacklist()
except Exception as e:
return Response(status=status.HTTP_400_BAD_REQUEST)
models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class CustomUserManager(BaseUserManager):
def create_superuser(self, email, password, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
if other_fields.get('is_staff') is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if other_fields.get('is_superuser') is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
return self.create_user(email, password, **other_fields)
def create_user(self, email, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, **other_fields)
user.set_password(password)
user.save()
return user
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
# REQUIRED_FIELDS = ['user_name', 'first_name']
def __str__(self):
return self.email
In your CustomUser model you are the is_active field is defined with default=False, you can change it to default=True or set the user to active during the registration process.
I want to login with email not username like this, please help
class loginUser(View):
def get(self, request):
lF = loginForm
return render(request, 'UserMember/login.html', {'lF': lF})
def post(self, request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'UserMember/private.html')
else:
return HttpResponse('login fail')
First thing is to create a default email field.
# models.py
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
# settings.py (remember to migrate)
AUTH_USER_MODEL = 'accounts.CustomUser' # new
Next, create your custom email backend:
# backends.py (in-app)
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserModel.objects.get(
Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
# settings.py (migrate again)
AUTH_USER_MODEL = 'accounts.CustomUser'
AUTHENTICATION_BACKENDS = ['accounts.backends.EmailBackend'] # new
If you plan on using Django's default register/login forms, do:
# form.py
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model
from django import forms
class RegisterForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('email', 'username', 'password1', 'password2')
class LoginForm(AuthenticationForm):
username = forms.CharField(label='Email / Username')
And then it's only the views and URLs to handle.
Ref
you need to work with allAuth
Follow this Link
hope it will be helpful.
the code below is a simple register for an account now when I submit this form it redirects me to the home page and this means that my form is valid and works but when I check my Admin page I see that account is not registered and I get no error. therefor I can understand here that my code is already working but it hasn't been saved.
so, how can I save member through FormView?
thanks in advance
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.views.generic import TemplateView, View
from django.views.generic.edit import FormView, CreateView
from .forms import UserForm
from .models import User
from django.urls import reverse_lazy
class IndexView(TemplateView):
template_name = "accounts/index.html"
class ProfileView(CreateView):
template_name = 'accounts/register.html'
success_url = reverse_lazy('accounts:index')
form_class = UserForm
forms.py
from django import forms
from .models import User
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label="Confirm Password", widget=forms.PasswordInput)
class Meta:
model = User
fields = '__all__'
exclude = ('staff', 'active', 'admin', 'last_login')
def clean_password2(self):
password = self.cleaned_data['password']
password2 = self.cleaned_data['password2']
if password and password2 and password != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def clean_email(self):
email = self.cleaned_data['email']
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
models.py
from django.db import models
from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager)
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserManager(BaseUserManager):
def create_user(self, email, password, username, is_staff=True, is_admin=True, is_active=True):
if not email:
raise ValueError("This email is invalid")
if not password:
raise ValueError("This Password is invalid")
if not username:
raise ValueError("This Username is invalid")
user = self.model(
email=self.normalize_email(email)
)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.set_password(password)
user.username = username
user.save(using=self._db)
return user
def create_staffuser(self, email, password, username):
user = self.create_user(
email,
password=password,
username=username,
is_staff=True,
)
return user
def create_superuser(self, email, password, username):
user = self.create_user(
email=email,
password=password,
username=username,
is_staff=True,
is_admin=True,
)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True, verbose_name="Email")
first_name = models.CharField(max_length=255, verbose_name="First Name")
last_name = models.CharField(max_length=255, verbose_name="Last Name")
username = models.CharField(max_length=50, unique=True, verbose_name="Username")
active = models.BooleanField(default=True, verbose_name="Active")
staff = models.BooleanField(default=False, verbose_name="Staff")
admin = models.BooleanField(default=False, verbose_name="Admin")
timestamp = models.DateTimeField(auto_now_add=True, verbose_name="Time Stamp")
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
objects = UserManager()
def __str__(self):
return self.username
def get_short_name(self):
return self.username
def get_full_name(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
article = models.TextField(blank=True, max_length=500, verbose_name="Article")
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = User.objects.create(user=kwargs['instance'])
post_save.connect(receiver=create_profile, sender=User)
Because a FormView doesn't save() the form. It's meant to be used with any form, not just ModelForms. Not every Form has a save() method.
The only thing the FormView does in form_valid() is redirect to the success url. You have to tell it yourself what you it to do after the form was verified to be valid:
def form_valid(self, form):
form.save()
return super().form_valid(form)
You can see the inner workings of FormView here.
You could use a CreateView instead of a FormView. That would do the saving for you.
I'm new in Django. I tried to make a registration with a custom user and I'm struggling with errors.
views.py
from django.shortcuts import render
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse,HttpResponseRedirect
from django.contrib.auth import authenticate,login,logout
from django.views.generic import FormView,TemplateView,ListView
from .forms import RegisterForm
from .models import User
# Create your views here.
#user-login view
def register(request):
registred=False
if request.method=="POST":
user_register=RegisterForm(data=request.POST)
if user_register.is_valid():
user=User.save()
user.set_password(user.password)
user.save()
registred=True
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse('there is a problem')
else:
return render(request,'register.html',{'registred':registred,'user_register':RegisterForm})
def user_login(request):
if request.method=='POST':
email=request.POST.get('email')
password=request.POST.get('password')
user=authenticate(email=email,password=password)
if user is not None:
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse("Account not found")
else:
return render(request,'login.html')
#user-logout view
#login_required
def user_logout(request):
logout(request)
return HttpResponseRedirect(reverse('index'))
#registration view
models.py
# accounts.models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
# accounts.models.py
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, email, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.admin = True
user.save(using=self._db)
return user
# hook in the New Manager to our Model
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
username=models.CharField(default='',unique=True,max_length=50)
full_name=models.CharField(default='',max_length=50)
short_name=models.CharField(default='',max_length=50)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
# notice the absence of a "Password field", that is built in.
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # Email & Password are required by default.
def get_full_name(self):
# The user is identified by their email address
return self.full_name
def get_short_name(self):
# The user is identified by their email address
return self.short_name
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
return self.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
objects = UserManager()
the error :
TypeError at /register/
save() missing 1 required positional argument: 'self'
From views.py, remove user=User.save(), which is invalid not having an instance (that self which is missing)
user_register=RegisterForm(data=request.POST)
if user_register.is_valid():
user = User()
user.set_password(user.password)
user.save()
registred=True