I want to do ajax form validation to display errors. I looked at many examples, but some are old and do not work, while others I do not understand.Below is the code, please help with the implementation of ajax requests.
views.py
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_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()
return HttpResponse('IZI')
else:
print(user_form.errors)
user_form = UserRegistrationForm()
# errors = user_form.errors
data = {'user_form': user_form, 'errors': user_form.errors}
return render(request, 'registration.html', data)
# return HttpResponse(simplejson.dumps(errors))
else:
user_form = UserRegistrationForm()
return render(request, 'registration.html', {'user_form': user_form})
models.py
class TestUser(AbstractUser):
phone = PhoneNumberField(null=False, blank=False, unique=True)
class Meta:
db_table = '"fyzzys"."users"'
forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat password', widget=forms.PasswordInput)
phone = PhoneNumberField(region='RU', required='true')
email = forms.CharField(error_messages='')
class Meta:
model = TestUser
fields = ('username', 'first_name', 'email', 'phone')
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('Passwords don\'t match.')
return cd['password2']
Here is an example but you'll need to adapt it to your needs and your code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js">
$.ajax({
url: 'your_url_for_register_view',
data: { password : 'your_password',
password2 : 'your_password',
phone : 'your_phone',
email : 'your_email',
csrfmiddlewaretoken : {{ csrf_token }},
},
success: function (data) {
//do something if successful
}
});
</script>
As per documentation : https://simpleisbetterthancomplex.com/tutorial/2016/08/29/how-to-work-with-ajax-request-with-django.html
Related
I want to sign in to be able to use the site. However, I'm having a problem: 'LoginForm' object has no attribute 'cleaned_data'. Please tell me how can I solve it. I apologize in advance for my English
My forms.py
class LoginForm(forms.Form):
user_name = forms.CharField(max_length=20, widget=TextInput(attrs={'type':'text','class': 'form-control','placeholder': 'Input username'}))
passWord = forms.CharField(max_length=25, widget=TextInput(attrs={'type':'password','class': 'form-control','placeholder': 'Input password'}))
class Meta:
fields = ['user_name', 'passWord']
My views.py
def login_view(request):
template_name = 'main/login.html'
action_detail = ''
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid:
username = form.cleaned_data.get('user_name')
password = form.cleaned_data.get('passWord')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/')
else:
action_detail = 'invalid username or password'
else:
form = LoginForm()
context={
'title': 'Login',
'form': form,
'action_detail': action_detail,
}
return render(request, template_name, context)
is_valid is a function.
https://docs.djangoproject.com/en/4.0/ref/forms/api/#django.forms.Form.is_valid
You should call it.
if form.is_valid():
I am trying to make a registration form for a dentist and a student, where I have a choice field for a dentist and a student. What I want to happen is, when dentist is picked, I should be able to see the specialties field in the html as well as Django to pick that form, and for student, to pick student_email and institution. I am confused to how to write its code in the template and I looked almost everywhere and couldn't find anything that could help with what I want. I also included an image with what the registration image looks like. I know I can use select and option in html template but still a bit confused about them as well. If you could show me a better way to apply my idea, please let me know.
form.py
from django import forms
from django_countries.fields import CountryField
class RegistrationForm(forms.Form):
Specialties = [
('pediatric','Pediatric'),
('oral surgeon','Oral Surgeon'),
('periodontist','Periodontist (Restorative; Esthetic)'),
('orthodontist','Orthodonsit'),
('endodontist','Endodontist'),
('prosthodontist','Prosthodontist'),
('oral pathologist','Oral Pathologist'),
('oral radiologist','Oral Radiologist'),
('public health dentist','Public Health Dentist'),
('research and academics','Research and Academics'),
]
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}), required=True, unique=True)
email = forms.EmailField(widget=forms.EmailInput(attrs={'class':'form-control'}), required=True, unique=True)
student_email = forms.EmailField(widget=forms.EmailInput(attrs={'class':'form-control'}), required=True, unique=True)
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}), required=True)
password_repeat = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}), required=True)
first_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}), required=True)
last_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}), required=True)
date_of_birth = forms.DateField(label = "Date of Birth", widget=forms.SelectDateWidget([x for x in range(1920,2021)]), required=True)
country = CountryField().formfield(required=True)
gender = forms.ChoiceField(widget=forms.RadioSelect, choices=[('male','Male'),('female','Female')], required=True)
specialty = forms.CharField(widget=forms.Select(choices= Specialties), required=True)
institution = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}), required=True)
dentist_or_student = forms.ChoiceField(widget=forms.RadioSelect, choices=[('dentist','Dentsit'),('student','Student')], required=True)
def clean_student_email(self):
data = self.cleaned_data['student_email']
if "#edu" not in data: #Check if the student's email is educational or not
raise forms.ValidationError("Email must be #edu")
return data
views.py
def user_register(request):
template_name = 'accounts/signup.html'
if request.method == 'POST':
form = RegistrationForm(request.POST)
# Check for validity
if form.is_valid():
if form.cleaned_data['dentist_or_student'] == 'dentist':
if User.objects.filter(username=form.cleaned_data['username']).exists():
return render(request, template_name, {
'form': form,
'error_message': 'Username already exists'
})
elif User.objects.filter(email=form.cleaned_data['email']).exists():
return render(request, template_name, {
'form': form,
'error_message': 'Email already exists'
})
elif form.cleaned_data['password'] != form.cleaned_data['password_repeat']:
return render(request,template_name, {
'form': form,
'error_message': 'Passwords do not match'
})
else:
# Create the user
user = User.objects.create_user(
form.cleaned_data['username'],
form.cleaned_data['email'],
form.cleaned_data['password']
)
user.first_name = form.cleaned_data['first_name']
user.last_name = form.cleaned_data['first_name']
user.dentist_or_student = form.cleaned_data['dentist']
user.date_of_birth = form.cleaned_data['date_of_birth']
user.country = form.cleaned_data['country']
user.gender = form.cleaned_data['gender']
user.save()
# Login the user
login(request, user)
# redirect to Homepage
return HttpResponseRedirect('home')
elif form.cleaned_data['dentist_or_student'] == 'student':
if User.objects.filter(username=form.cleaned_data['username']).exists():
return render(request, template_name, {
'form': form,
'error_message': 'Username already exists'
})
elif User.objects.filter(email=form.cleaned_data['student_email']).exists():
return render(request, template_name, {
'form': form,
'error_message': 'Email already exists'
})
elif form.cleaned_data['password'] != form.cleaned_data['password_repeat']:
return render(request,template_name, {
'form': form,
'error_message': 'Passwords do not match'
})
else:
# Create the user
user = User.objects.create_user(
form.cleaned_data['username'],
form.cleaned_data['student_email'],
form.cleaned_data['password']
)
user.first_name = form.cleaned_data['first_name']
user.last_name = form.cleaned_data['first_name']
user.dentist_or_student = form.cleaned_data['student']
user.date_of_birth = form.cleaned_data['date_of_birth']
user.country = form.cleaned_data['country']
user.gender = form.cleaned_data['gender']
user.save()
# Login the user
login(request, user)
# redirect to Homepage
return HttpResponseRedirect('home')
else:
messages.error(request, 'Please pick if either you are a Dentist or a Student before continuing the form')
return redirect('register')
# No post data available, just show the webpage
else:
form = RegistrationForm()
return render(request, template_name, {'form': form})
enter image description here
You are using a CharField (see docs) for a field that has options. Try using a ChoiceField (see docs) instead.
Something like:
specialty = forms.ChoiceField(choices= Specialties, required=True)
You should add both into your html, and make them hidden.
Then add an alert into your Select, and OnChange you can make hidden=false of the selected form.
YOURSELECT.addEventListener("change", document.getElementById(YOURSELECT.value).removeAttribute("hidden"););
I have created an extended User model and a form to register it. Since the form is filled out by an admin and not a user, the UserCreationForm has a random password generator to fill out password1 and 2, then set new password. This is great for a new user, but every time an admin edits the user profile, it will set a new password. I've looked at a few dozen examples here and on big G but can't seem to find a usable solution to know if the user has a password set.
I am re-using this form for update view, which is where I don't want the random password to be generated again. I tried doing the same if statement check as the username but it doesn't work the same way as the auth\form.py user.set_password is looking for password1.
class EmployeeRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class': 'form-control mb-2',
'placeholder': 'Email address'}))
first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control mb-2',
'placeholder': 'First name'}))
last_name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': 'Last name'}))
password1 = None
password2 = None
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
def clean(self):
password = User.objects.make_random_password(length=10,
allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
self.cleaned_data['password1'] = password
self.cleaned_data['password2'] = password
return super().clean()
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if user.username == '':
if len(user.first_name.split()) and len(user.last_name.split()) > 1:
username = f'{"".join(user.first_name.split()[:2])}{"."}{"".join(user.last_name.split())}'
elif len(user.first_name.split()) > 1:
username = f'{"".join(user.first_name.split()[:2])}{"."}{user.last_name}'
elif len(user.last_name.split()) > 1:
username = f'{user.first_name}{"."}{"".join(user.last_name.split())}'
else:
username = f'{user.first_name}{"."}{user.last_name}'
username = username.lower()
user.username = username
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
Update
Here is the profile_edit view where I verify the details of an existing user and save changes made through the form.
#login_required()
def profile_edit(request, slug, *args, **kwargs):
"""
Used for updating the Employee profile
"""
employee = Employee.objects.get(slug=slug)
employee_user = User.objects.get(id=employee.user.id)
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
if 'cancel' in request.POST:
return redirect('corehr:employees')
elif request.method == 'POST':
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
if form.is_valid() and user_form.is_valid():
form.save(commit=False)
user_form.save()
form.save()
messages.success(request, f'{employee.get_full_name}{" was updated successfully."}')
return redirect(reverse_lazy('corehr:profile', kwargs={'slug': slug}))
else:
messages.error(request, 'Please correct the errors listed below')
else:
form = EmployeeForm(request.POST or None, request.FILES or None, instance=employee)
user_form = EmployeeRegistrationForm(request.POST or None, instance=employee_user)
context = {'form': form, 'user_form': user_form}
return render(request, 'coreHR/profile_edit.html', context)
I ended up taking the suggestions from Abdul and Ranu. The are both right, so I just created a UserUpdateForm to update the data rather to 're-create' the user again. It all works as smooth as ever.
class UserUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
widgets = {
'email': forms.EmailInput(attrs={'class': 'form-control mb-2'}),
'first_name': forms.TextInput(
attrs={'class': 'form-control mb-2'}),
'last_name': forms.TextInput(
attrs={'class': 'form-control mb-2'}),
}
I replaced the reference in the profile_edit view from EmployeeRegistrationForm to UserUpdateForm. This was so simple an I was busting my head trying to work around several complex solutions which were going against the basics.
I'm creating a user update form in my app. but every time when the form is submitted , it creates a new record and if you try submitting again will return Integrity Error(duplicate username that both are null).
ERROR message: django.db.utils.IntegrityError: UNIQUE constraint failed: auth_user.username
forms.py:
class UserChangeForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'first_name', 'last_name']
def __init__(self, username, *args, **kwargs):
super(UserChangeForm, self).__init__(*args, **kwargs)
self.username = username
views.py:
def profile(request):
user = request.user
if request.method == 'POST':
user_form = UserChangeForm(user, request.POST)
if user_form.is_valid():
user_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('users:profile')
else:
email = request.user.email
first_name = request.user.first_name
last_name = request.user.last_name
user_form = UserChangeForm(user, initial={
'email': email,
'first_name': first_name,
'last_name': last_name
})
context = {
'user_form': user_form,
}
return render(request, 'users/profile.html', context)
you need to pass the user as instance in the if condition and in else too like this
def profile(request):
if request.method == 'POST':
user_form = UserChangeForm(request.POST , instance = request.user)
if user_form.is_valid():
user_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('users:profile')
else:
user_form = UserChangeForm(instance=request.user)
context = {
'user_form': user_form,
}
return render(request, 'users/profile.html', context)
I have a registration that let users register and i'm having difficulty fixing it.
The problem is when a user submits a single field instead of the whole form for example an email . I get this error
KeyError at /register/
password
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _get_errors
115. self.full_clean()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in full_clean
271. self._clean_form()
File "C:\Python26\Lib\site-packages\django\forms\forms.py" in _clean_form
299. self.cleaned_data = self.clean()
File "C:\o\17\mysite\pet\forms.py" in clean
31. if self.cleaned_data['password'] != self.cleaned_data['password1']:
Exception Type: KeyError at /register/
Exception Value: password
I tried to fix this solution using if . If user has a submitted a username or any other required field , process the form otherwise redisplay the original form.
but I still get the same error.
This is my edited views.py (at the bottom of the page is my original RegistrationForm)
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
if username:
email=form.cleaned_data['email']
if email:
password=form.cleaned_data['password']
if password:
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
How can I fix this error and also how could I display an error message on the other fields that the user didn't fill out like "Error Missing Field , Please Fill this Field".
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
if request.method =='POST':
form = UserRegistration(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': UserRegistration()})
My forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
"That user is already taken , please select another ")
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
My models.py
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100, blank=True)
birthday = models.DateField(blank=True,null=True)
def __unicode__(self):
return self.name
Problem is with your clean(). In clean(), you are trying to access field password on form's cleaned_data. password will only be available on cleaned_data if the user has filled this field. So, you must check that password is there in cleaned_data before trying to access it.
Changing your clean():
def clean(self):
if 'password' in self.cleaned_data and 'password1' in self.cleaned_data and self.cleaned_data['password'] != self.cleaned_data['password1']:
raise forms.ValidationError("The password does not match ")
return self.cleaned_data
You can provide a keyword argument error_messages on form field for showing error message like "Error Missing Field , Please Fill this Field".
class SomeForm(forms.Form):
name = forms.CharField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
There is a bug in your view.
is_valid() populates errors on the form but this same form instance must be sent to the template so that you can access the errors on the form's fields.
But in your view, you have only one call to render() which gets called even in case of an invalid form on a post request. And in this render(), you are creating a new instance of form. So, this new form which you are sending to template will not have any errors.
So, making slight modification to your view:
def PetRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:HappyLand'))
form = UserRegistration() #This will be used in GET request
if request.method =='POST':
form = UserRegistration(request.POST) #This will be used in POST request
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.is_active = True
user.first_name = form.cleaned_data['name']
user.save()
person = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password']
)
Person.objects.create(user_id=user.id,
name=form.cleaned_data['name'],birthday=form.cleaned_data['birthday'])
login(request, person)
return HttpResponseRedirect(reverse('world:HappyLand'))
return render(request, 'register.html', {'form': form})
Notice in your view, I have added form=UserRegistration() before checking if its POST request, and have added the comment at two places where we are instantiating UserRegistration. And then in render(), you should send this form.
Then your {{form.username.errors}} will work.
I just modified your forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
name = forms.CharField()
email = forms.EmailField()
birthday = forms.DateField(widget=extras.SelectDateWidget(years=range(1950, 2012)))
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
password1 = forms.CharField(
label=(u'Verify Password'),
widget = forms.PasswordInput(render_value=False)
)
def clean(self):
cleaned_data = super(UserRegistration, self).clean()
username = cleaned_data.get("username")
password = cleaned_data.get("password")
password1 = cleaned_data.get("password1")
#check if username exist
user = User.objects.filter(username=username)
if user:
raise forms.ValidationError(
"That user is already taken , please select another ")
#check password
if password != password1:
raise forms.ValidationError(
"Your current and confirm password do not match.")
return cleaned_data