i want to make login social auth and i use userprofile to login, but i getting error. This is error:
Exception Type: TypeError at /complete/facebook/
Exception Value: create_user() takes at least 3 arguments (2 given)
this is my admin.py code
class CustomUserCreationForm(UserCreationForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)
class Meta(UserCreationForm.Meta):
model = UserProfile
fields = ('username', 'email','password')
def clean_username(self):
username = self.cleaned_data["username"]
try:
UserProfile._default_manager.get(username=username)
except UserProfile.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords do not match.")
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
this is model.py
class MyUserManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not email:
raise ValueError('Users must have an email address')
if not username:
raise ValueError('Users must have a username')
user = self.model(
username = username,
email = self.normalize_email(email),
)
user.is_active = True
user.set_password(password)
user.save(using=self._db)
return user
# def create_user(self, username, email):
# return self.model._default_manager._create_user(username=username)
def create_superuser(self, username, email, password):
user = self.create_user(username=username, email=email, password=password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
i already put password in fields class Meta(UserCreationForm.Meta) but its still same error.
can you help me solve this problem?
As the error mentions, create_user() expects at least three arguments but you provide only two (username and email) while defining fields. Django documentation covers this pretty well. Try adding a password field and see if it works.
Related
I'm learning Django and tried to write my own custom user model. I'm not using DRF and serializers and stuffs I have no idea about :)
I am using createView to create users but I can't login because "Invalid password."
I checked the user's password in admin and the user's password is "Invalid password format or unknown hashing algorithm." .
here are the codes:
Custome User and User Manager in models
class UserManager(UserManager):
def create_user(self, username, email, password, **extra_fields):
if not email:
raise ValueError('User must have email')
if not username:
raise ValueError('User must have username')
user = User.objects.create_user(
username=username,
email=self.normalize_email(email),
)
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password, **extra_fields) :
user = self.create_user(username, email, password)
user.is_staff = True
user.is_superuser = True
user.is_admin = True
user.is_active = True
user.save()
return user
class User(AbstractBaseUser):
username = models.CharField(unique=True, max_length=200)
email = models.EmailField(unique=True)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
modified_at = models.DateTimeField(auto_now=True)
objects = UserManager()
REQUIRED_FIELDS = ["username","email", "password"]
USERNAME_FIELD = "username"
def __str__(self):
return self.email
def has_perm(self, perm, object=None):
"Does the user have a specific permission?"
return self.is_admin
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
SignUp and login in views
class SignUp(CreateView):
model = User
form_class = CUForm
success_url = reverse_lazy('index')
def login(request):
if request.user.is_authenticated:
messages.warning(request, 'You are already logged in.')
return redirect('/list')
elif request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('/list')
else:
try:
user = User.objects.get(username=username)
messages.error(request, 'Invalid password.')
except:
messages.error(request, 'Invalid username ')
return redirect('login')
return render(request, 'accounts/login.html')
and forms.py
class CUForm(forms.ModelForm):
username = forms.CharField(max_length=200)
email = forms.EmailField(widget=forms.EmailInput())
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ['email','username','password',]
def clean(self):
cleaned_data = super(CUForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password != confirm_password:
raise forms.ValidationError('Password does not match.')
and admin
class CostumeUserAdmin(UserAdmin):
list_display = ('email', 'username', 'is_active', 'is_admin')
filter_horizontal = ()
list_filter = ('is_staff',)
fieldsets = ()
admin.site.register(User, CostumeUserAdmin)
I have read some of the solutions and I changed
user = self.model(
username=username,
email=self.normalize_email(email)
)
to
user = User.objects.create_user(
username=username,
email=self.normalize_email(email),
)
Alrigh I have fixed the "Invalid password format or unknown hashing algorithm." issue by adding this to my createView:
def form_valid(self, form):
user = form.save(commit=False)
password = self.request.POST['password']
user.set_password(password)
user.save()
return super().form_valid(form)
and the password now saves correctly, not sure why but it does.
And then I realized I didn't add AUTH_USER_MODEL = 'accounts.User'
in my setting.py!
I still don't know why I need to use set_password in form_valid even tho I used it in UseManager but now It works!
Basically what I have done so far is create a registration page where the user makes their username and password, then that password is stored in as a hashed password (md5 hasher). The problem I am having is logging in. The user inputs their username and password then the password is authenticated by using authenticate() method in django. The problem is that authenticate() is returning None instead of matching the user and password in the database. I dont know if this affects anything but I am using PostgreSQL.
models.py
class MyAccountManager(BaseUserManager):
def create_user(self, email,username,first_name,password= None):
if not email:
raise ValueError('User must have an email address')
if not username:
raise ValueError('User must have a username')
if not first_name:
raise ValueError('User must have a first name')
user= self.model(
email=self.normalize_email(email),
username= username,
first_name= first_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, password):
user= self.create_user(
email= self.normalize_email(email),
username=username,
first_name= first_name,
password= password,
)
user.is_admin= True
user.is_staff= True
user.is_superuser= True
user.save(using=self._db)
return user
class User(AbstractBaseUser, models.Model):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='date joined')
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
USERNAME_FIELD= 'username'
REQUIRED_FIELDS= ['email','first_name']
objects= MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
forms.py
class LoginForm(forms.Form):
username = forms.CharField(initial='' ,label='Username:',max_length=30)
password = forms.CharField(max_length=20, widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'password')
def clean(self):
cleaned_data = super(LoginForm, self).clean()
confirm_password = cleaned_data.get('password')
class SignUpForm(forms.ModelForm):
first_name = forms.CharField(required= True,initial='',max_length=20)
last_name = forms.CharField(required=True,max_length=30, initial='')
username = forms.CharField(max_length=30,initial='', required=True)
password = forms.CharField(max_length= 20, initial='', widget = forms.PasswordInput())
password2= forms.CharField(max_length=20, initial='',widget = forms.PasswordInput())
email = forms.EmailField(max_length=60, initial='',)
class Meta:
model = User
fields = ('first_name', 'last_name','username','password2','email')
def clean(self):
cleaned_data = super(SignUpForm,self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('password2')
if(password != confirm_password):
raise forms.ValidationError(
'Password and Confirm Password do not match.'
)
views.py
def signin_and_signup(request):
if request.method == 'POST':
logout(request)
sign_in = LoginForm(request.POST)
signup = SignUpForm(request.POST)
if 'sign-in-name' in request.POST:
if sign_in.is_valid():
username = request.POST.get('username')
password= request.POST.get('password')
user = authenticate(username= username, password= password)
if user:
return HttpResponse('success')
else:
return HttpResponse('fail')
elif 'sign-up-input-name' in request.POST:
if(signup.is_valid()):
user = signup.save(commit=False)
nonHashed = signup.cleaned_data['password']
varhash = make_password(nonHashed, None, 'md5')
user.set_password(varhash)
user.save()
else:
print("Ran3<------------")
signup = SignUpForm()
else:
sign_in = LoginForm()
signup = SignUpForm()
context = {'signin':sign_in, 'signup':signup}
return render(request, 'home.html', context)
Why are you substituting the user model that django provides if you have the same attributes?
This is done in case you want to extend or add new properties to the user, for example, license number, avatar, position.
Anyway, your authenticate() maybe doesn't work because you haven't registered your new model in settings.py.
AUTH_USER_MODEL = 'name_of_the_app.User'
I recommend that you take a look at the official documentation
https://docs.djangoproject.com/en/3.1/topics/auth/customizing/
Antoher thing it could be your authentication backend:
Try:
settings.py
AUTHENTICATION_BACKENDS = [
'name_of_the_app.admin.LoginBackend',
]
Where you want for example admin.py
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class LoginBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try: # to allow authentication through phone number or any other field, modify the below statement
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return models.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
As you can see, you can also login with the email
The problem is when i try to register this error show up:
django.db.utils.IntegrityError: NOT NULL constraint failed: accounts_user.password
I tried to migrate and did all recommended things like migrations but it didn't work.
This is my files
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 django.conf import settings
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():
username=user_register.cleaned_data.get('username')
email=user_register.cleaned_data.get('email')
password=user_register.cleaned_data.get('password1')
user=User.objects.create(username=username,email=email,password=password)
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
forms.py:
# accounts.forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email','username','full_name','short_name','password')
def clean_username(self):
username = self.cleaned_data.get('username')
if User.objects.filter(username__iexact=username).exists():
raise forms.ValidationError('This username already exists')
return username
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
class UserAdminCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'active', 'admin')
def clean_password(self):
return self.initial["password"]
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()
i just changed this password=user_register.cleaned_data.get('password') to this password=request.POST.get('password') and it worked
I'm using Django-rest-framework for my projects.
I wanted that when users intend to login and get the access token, if user enter wrong username or password for third time, their accounts get deactivated and an email containing activation link would be send to their email. Anyone can guide me to implement this scenario?
models.y
class CustomUserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, mobile_number, password, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
mobile_number = mobile_number
user = self.model(email=email, mobile_number= mobile_number **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, mobile_number, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, mobile_number, password, **extra_fields)
def create_superuser(self, email, mobile_number, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_active') is not True:
raise ValueError('Superuser must have is_active=True.')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, mobile_number, password, **extra_fields)
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True, validators= [validate_email])
mobile_number = models.CharField(_("mobile number"), max_length=11, unique = True, validators= [validate_mobile_number])
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['mobile_number']
objects = CustomUserManager()
def __str__(self):
return self.email
def get_full_name(self):
return "{} {}".format(self.first_name, self.last_name)
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', 'mobile_number', 'is_active', 'is_staff', 'is_superuser']
def validate_mobile_number(self, value):
if mobile_number_pattern.match(value):
return value
else:
raise ValidationError('Mobile number pattern is not correct.')
class LoginSerializer(serializer.Serializer):
email = serializer.ChaerField()
password = serializer.CharField()
def validate(self, data):
if email and password:
user = authenticate(email= email, password= password)
if user:
if user.is_active:
data["user"] = user
else:
raise exceptions.ValidationError("User is deactivated.")
else:
raise exceptions.ValidationError("unable to login")
else:
raise exceptions.ValidationError("Must provide email and password both.")
return data
Views.py (api views)
from rest_framework.views import APIView
form .serializers import LoginSerializer
from django.contrib.auth import login, logout
from rest_framework.authtoken.models import Token
class LoginView(APIView):
def post(self, request):
serializer = LoginSerializer(data= request.data)
serializer.is_valid(raise_exception= True)
user = serializer.validated_data["user"]
login(request, user)
token, created = Token.objects.get_or_create(user=user)
return Response({"Token": token.key}, status= 200)
I created a custom user model because i needed the user to sign in using email instead of username. If a user signs up on the frontend, the password is hashed just fine but when i try to create a password from Django's backend, the password is saved as plain text.
admin.py
def save(self, commit=True):
# Save the provided password in hashed format
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
forms.py
class RegisterForm(forms.ModelForm):
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password = self.cleaned_data.get("password")
password2 = self.cleaned_data.get("password2")
if password and password2 and password != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
user.set_password(self.cleaned_data['password'])
# user.is_applicant = True
user.is_active = True
if commit:
user.save()
return user
Please for some assistance.
Maybe you should create the user using the official function see create_user . https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.UserManager.create_user
Edit your def save to this in your User creation form in admin.py,
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user