In an extended user model with User and Profile created together. The user and related profile(Customer) is created but two fields 'email'(user email) field and 'photo'(image field) is not saved into database. Appreciate some fix:
views.py
def customer_register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
profile_form = CustomerProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# Set the chosen password
new_user.set_password(
user_form.cleaned_data['password'])
# Save the User object
new_user.save()
# Create the customer profile
customer = profile_form.save(commit=False)
customer.user = new_user
customer.save()
#Customer.objects.create(user=new_user,date_of_birth=customer.date_of_birth, photo=customer.photo, pincode=customer.pincode)
return render(request,
'registration/register_done.html',
{'new_user': new_user})
else:
messages.error(request, 'Error in creating your profile')
else:
user_form = UserRegistrationForm()
profile_form = CustomerProfileForm()
Forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password',
widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat password',
widget=forms.PasswordInput)
email = forms.EmailField(label='email', widget=forms.EmailInput, required=True)
class Meta:
model = User
fields = ['username', 'first_name', 'email']
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
def clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Email exists. Please change email")
class CustomerProfileForm(forms.ModelForm):
pincode = INZipCodeField(label="PIN")
date_of_birth = forms.DateField(widget=forms.DateInput(format='%d/%m/%Y'), input_formats=('%d/%m/%Y',))
photo = forms.ImageField()
class Meta:
model = Customer
fields = ['pincode','date_of_birth','photo']
I figured out the email id issue was in the form, form had to return the email in the email validation function
clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Email exists. Please change email")
return email
In the views I had to add request for files(image) along with form:
profile_form = CustomerProfileForm(request.POST, request.FILES or None)
The image issue was in the registration html template. I updated the form to enctype "multipart/form-data" to take get image inputs
<form method="post" enctype="multipart/form-data" action="{% url 'customer_register' %}">
{% csrf_token %}
Related
I'm new to Django, I have a registration form, Everything works fine If I fill all fields and when I don't fill all the fields. But when I submit a form without a username field I get a "Key Error" instead of "This field is required" Exception since I have declared the field is required on the form class.
forms.py
class UserRegistration(forms.ModelForm):
first_name = forms.CharField(label='First Name', max_length=50)
last_name = forms.CharField(label='Last Name', max_length=50)
username = forms.CharField(label='Username', max_length=50)
email = forms.EmailField(label='Email', max_length=50)
password = forms.CharField(label='Password', widget=forms.PasswordInput, max_length=50, validators = [validators.MinLengthValidator(6)])
password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput, max_length=50)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password', 'password2')
def clean_username(self):
username = self.cleaned_data['username']
email = self.cleaned_data['email']
if username and User.objects.filter(username=username).exclude(email=email).count():
raise forms.ValidationError('This username address is already in use.')
return username
def clean_email(self):
email = self.cleaned_data['email']
username = self.cleaned_data['username']
if email and User.objects.filter(email=email).exclude(username=username).count():
raise forms.ValidationError('This email address is already in use.')
return email
def clean_password(self):
password = self.cleaned_data['password']
if len(password) < 6:
raise forms.ValidationError("Password is too short")
return password
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
views.py
def register(request):
if request.method == 'POST':
form = UserRegistration(request.POST)
if form.is_valid():
new_user = form.save(commit=False)
new_user.set_password(
form.cleaned_data.get('password')
)
new_user.save()
return render(request, 'authapp/register_done.html')
else:
return render(request, 'authapp/register.html', {'form':form})
else:
form = UserRegistration()
context = {
"form": form
}
return render(request, 'authapp/register.html', context=context)
Error Traceback
Error Page Screenshot
Request Information Post data
When creating Form, update the username field with required and Null
Yes, by default required will be True but it is a constraint for the DB side while the 'null' field is used when any widget is must from UI side
username = forms.CharField(label='Username', max_length=50,required=True,null=False)
And about error you got : username validator is saving empty name so empty data is accessed and used in email validation
After googling and researching "KeyError" Exception, I have found that the error is caused by accessing a dictionary value with a key 'username' that doesn't exist, hence the KeyError. So it's more of a programming error than Django itself. The solution is to check for the key if it exists before accessing it or use
username = self.cleaned_data.get('username')
instead of
username = self.cleaned_data['username']
according to https://www.journaldev.com/33497/python-keyerror-exception-handling-examples#:~:text=We%20can%20avoid%20KeyError%20by,when%20the%20key%20is%20missing.
I have made a form having fields of personal information and login information as one
models.py
class EmployeeModel(models.Model)
employee_id = models.CharField(max_length=300,unique=True,help_text='Employee ID should not be same')
name = models.CharField(max_length=300)
username = models.CharField(max_length=50,null=True,blank=True)
email = models.EmailField(null=True,blank=True)
password = models.CharField(max_length=20,null=True,blank=True)
password_confirm = models.CharField(max_length=20,null=True,blank=True)
forms.py
class EmployeeForm(forms.ModelForm):
class Meta:
model = employeeModel
fields = ('__all__')
views.py
User = get_user_model()
def create_view(request):
if request.method == 'POST':
form = employeeForm(request.POST or None,request.FILES or None)
if form.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
User= get_user_model()
user= User.objects.create_user(username=username,email=email,password=password)
authenticate(request,username=username,email=email,password=password)
form.save()
return redirect('emp_list')
else:
form = employeeForm()
return render(request,'create_employee.html',{'form':form})
Its not showing any error but User.objects.all() shows only superuser not the users i created though this form. Those users i have created in this form are are showing up in Employee.objects.get(username='foo')
So what to do? I cant login through those non_superusers. it throws invalid login error. How to fix this?
I have a model with a field called in is_student and is_teacher Student and Teacher forms
is_teacher = models.BooleanField('teacher status', default=False)
is_student = models.BooleanField('student status', default=False)
I want to make sure this field is:
Always Checked by the user True *Required
Currently: is_teacher in TeacherApplications Model
When unchecked - it saved 0 to the form and continues. (Not good)
When checked gives me this error:
ValueError at /register/teacher invalid literal for int() with base
10: ''
Currently: is_student in StudentProfile Model
When checked gives this error
ValidationError at /register/ ["'on' value must be either True or
False."]
When unchecked it saved 0 to the form and continues. (Again, not good)
UPDATED CODE
Above errors are gone: New error each time I try to submit form after checking is_teacher/is_student
IntegrityError at /register/ NOT NULL constraint failed:
accounts_studentprofile.is_student
model
class StudentProfile(models.Model):
user = models.OneToOneField('Accounts', related_name='student_profile')
# additional fields for students
AMEB_Ratings = models.PositiveIntegerField(default=0)
is_student = models.BooleanField('student status', default=False)
class TeacherApplications(models.Model):
user = models.OneToOneField('Accounts', related_name='teacher_profile')
# additional fields for teachers
instrument = models.TextField(max_length=500, blank=True)
skill = models.CharField(max_length=30, blank=True)
experience_in_years = models.PositiveIntegerField(blank=True)
is_teacher = models.BooleanField('teacher status', default=False)
view
def registerStudent(request):
# Once register page loads, either it will send to the server POST data (if the form is submitted), else if it don't send post data create a user form to register
if request.method == "POST":
user_form = UserForm(request.POST)
form = StudentResistrationForm(request.POST)
if form.is_valid() and user_form.is_valid():
User = get_user_model()
username = user_form.cleaned_data['username']
email = user_form.cleaned_data['email']
password = user_form.cleaned_data['password']
new_user = User.objects.create_user(username=username, email=email, password=password)
student = form.save(commit=False)
student.user = new_user
student.save()
# Student_profile = StudentProfile()
# Student_profile.user = new_user
# Student_profile.AMEB_Ratings = request.POST['AMEB_Ratings']
# Student_profile.is_student = request.POST.get('is_student', False)
new_user.save()
# Student_profile.save()
# form.save()
return redirect('/')
else:
# Create the django default user form and send it as a dictionary in args to the reg_form.html page.
user_form = UserForm()
form = StudentResistrationForm()
# args = {'form_student': form, 'user_form': user_form }
return render(request, 'accounts/reg_form_students.html', {'form_student': form, 'user_form': user_form })
def teacherApplication(request):
# Once register page loads, either it will send to the server POST data (if the form is submitted), else if it don't send post data create a user form to register
if request.method == "POST":
user_form = UserForm(request.POST)
form = TeacherRegistrationForm(request.POST)
if form.is_valid() and user_form.is_valid():
User = get_user_model()
username = user_form.cleaned_data['username']
email = user_form.cleaned_data['email']
password = user_form.cleaned_data['password']
new_user = User.objects.create_user(username=username, email=email, password=password)
teacher = form.save(commit=False)
teacher.user = new_user
teacher.save()
# Teacher_profile = TeacherApplications()
# Teacher_profile.user = new_user
# Teacher_profile.instrument = request.POST['instrument']
# Teacher_profile.skill = request.POST['skill']
# Teacher_profile.experience_in_years = request.POST['experience_in_years']
# Teacher_profile.is_teacher = request.POST.get('is_teacher', False)
new_user.save()
# Teacher_profile.save()
# form.save()
return redirect('/')
else:
# Create the django default user form and send it as a dictionary in args to the reg_form.html page.
user_form = UserForm()
form = TeacherRegistrationForm()
return render(request, 'accounts/reg_form_teachers.html', {'form_student': form, 'user_form': user_form })
forms
class StudentResistrationForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = (
'AMEB_Ratings',
'is_student',
)
def save(self, commit=True):
user = super(StudentResistrationForm, self).save(commit=False)
# user.first_name = self.cleaned_data['first_name']
# user.last_name = self.cleaned_data['last_name']
user.AMEB_Ratings = self.cleaned_data['AMEB_Ratings']
if commit:
user.save()
return user
class TeacherRegistrationForm(forms.ModelForm):
class Meta:
model = TeacherApplications
fields = (
'instrument',
'skill',
'experience_in_years',
'is_teacher',
)
class UserForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = ('username', 'email', 'password')
You can add this fields to StudentResistrationForm and TeacherRegistrationForm and add custom validation for it in clean_fieldname method to make it required:
StudentResistrationForm(ModelForm):
class Meta:
model = StudentRegistration
fields = (
'instrument',
'skill',
'experience_in_years',
'is_student',
)
def clean_is_student(self):
is_student = self.cleaned_data.get('is_student')
if not is_student:
raise forms.ValidationError('This field is required')
return is_student
Also in view instead of getting raw data from request.POST you can use forms to create student and teacher objects:
new_user = User.objects.create_user(username=username, email=email, password=password)
teacher = form.save(commit=False)
teacher.user = new_user
teacher.save()
I'm using a view to create new users in Django. And then I have another view to log them in.
But when I create a user, and I try to log in with authenticate(username=username_post, password=password_post), I get None, so it displays in the template 'Wrong username or password.'.
In my database, I see new registers every time I create a new user. However, as the password is encrypted, I can't say if the problem is the login view, or the register view.
However, the super user that I created through the command line after I first installed django, is able to login with no problem, so that makes me thing that the problem is when I create the user.
These are my Login and Register views:
class Login(View):
form = LoginForm()
message = None
template = 'settings/blog_login.html'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated():
return redirect('settings:index')
return render(request, self.template, self.get_context())
def post(self, request, *args, **kwargs):
username_post = request.POST['username']
password_post = request.POST['password']
user = authenticate(username=username_post, password=password_post)
if user is not None:
login(request, user)
return redirect('settings:index')
else:
self.message = 'Wrong username or password.'
return render(request, self.template, self.get_context())
def get_context(self):
return {'form': self.form, 'message': self.message}
class Register(CreateView):
success_url = reverse_lazy('settings:login')
model = User
template_name = 'settings/blog_register.html'
form_class = RegisterForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.set_password(self.object.password)
self.object.save()
return HttpResponseRedirect(self.get_success_url())
And these are my forms:
class LoginForm(forms.Form):
username = forms.CharField(max_length=20, label='Username')
password = forms.CharField(label='Password', widget=forms.PasswordInput())
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=20, label='Username')
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.',
'unique': 'Username already used.',
'invalid': 'Not valid username.'})
password2 = forms.CharField(label='Retype password', widget=forms.PasswordInput(),
error_messages={'required': 'Required field.'})
email = forms.EmailField(error_messages={'required': 'Required field.',
'invalid': 'Invalid email.'})
def clean(self):
clean_data = super(RegisterForm, self).clean()
password1 = clean_data.get('password1')
password2 = clean_data.get('password2')
if password1 != password2:
raise forms.ValidationError('Passwords are different.')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(
username=username).exists():
raise forms.ValidationError('Email already used.')
return email
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'email')
Please, let me know if you need more info.
You don't have a field called 'password' in your form - you just have 'password1' and 'password2' - so nothing is saved to the model object's actual password field. So, when you do self.object.set_password(self.object.password), you're actually setting a blank password.
Instead, you should get the value from your form's password1 field:
self.object.set_password(self.form.cleaned_data['password1'])
I have a web application which has user registration and update user profile. I am using password hashers.
This is my models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
def __unicode__(self):
return self.user.username
This is my forms.py
class UserForm(forms.ModelForm):
username = forms.CharField(
max_length=254,
widget=forms.TextInput(attrs={'class': "form-control input-lg",'placeholder': 'username'}),
)
email = forms.CharField(
max_length=254,
widget=forms.TextInput(attrs={'class': "form-control input-lg",'placeholder': 'email'}),
)
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': "form-control input-lg",'placeholder': 'password'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': "form-control input-lg",'placeholder': 'confirm password'}),label="Confirm password")
class Meta:
model = User
fields = ('username', 'email', 'password','password2')
class UserProfileForm(forms.ModelForm):
website = forms.URLField(widget=forms.TextInput(attrs={'class': "form-control input-lg",'placeholder': 'website'}))
picture=form.Imagefield
class Meta:
model = UserProfile
fields = ('website', 'picture')
This is my views.py update and register
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
registered = True
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,
'Survey/register.html',
{'user_form': user_form, 'profile_form': profile_form, 'registered': registered} )
#login_required
def update(request):
updated = False
user = request.user
profile=request.userprofile
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
user_form = UserForm(data=request.POST,instance=user)
profile_form = UserProfileForm(data=request.POST,instance=profile)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
u = User.objects.get(username=user.username)
u.set_password(user.password)
u.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
update = True
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm(instance=user)
profile_form = UserProfileForm()
return render(request,
'Survey/update_profile.html.html',
{'user_form': user_form,'profile_form': profile_form,'updated': updated} )
I have two problems with this
I am able to retrieve the user information but not user profile information
The password field I updated is stored without hashing (during registration the password is stored with hashing) so I am unable to login with the new password as authentication fails
Any help?