django form is not valid but validation not working - django

When I submit form it doesn't show any validation error and form is not valid
views.py
def institute(request):
context = {}
if request.POST and request.FILES:
form = InstituteForm(request.POST, request.FILES)
context['form'] = form
if form.is_valid():
form.save()
messages.add_message(
request, messages.SUCCESS, "Successfully Added Institute Information")
return redirect('accounts:profile')
else:
context['form'] = InstituteForm()
return render(request, 'institute.html',context)
according to forms.py it should return email or phone validation error but there is no errors in template
and form data is saving in database
forms.py
class InstituteForm(forms.ModelForm):
class Meta:
model = Institute
fields = '__all__'
exclude = ('create', 'update', 'admin')
def clean_phone(self):
phone = self.cleaned_data['phone']
emp = Employee.objects.filter(phone=phone).count()
ins = Institute.objects.filter(phone=phone).count()
if emp > 0 or ins:
raise ValidationError('This Phone Number is already used, try new one')
return phone
def clean_email(self):
email = self.cleaned_data.get('email')
emp = Employee.objects.filter(email=email).count()
ins = Institute.objects.filter(email=email).count()
if ins > 0 or emp:
raise ValidationError('This email is already used, try new one')
return email

Related

ChoiceFields to give two different forms or different fields in html template and django

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"););

Django Form not saving for Custom User Model

I have a register user form which is doing all the validation as expected. However, it is not saving. I am not able to figure out the reason. How do I debug it ? Any help ? I am a newbie to forms and formviews any good document with example would really help me.
class RegisterForm(forms.ModelForm):
phone_number = forms.IntegerField(required=True)
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
country_code = forms.IntegerField()
#schools = school.objects.all()
#school_name = forms.ModelChoiceField(queryset=school.objects.distinct())
MIN_LENGTH = 4
class Meta:
model = User
fields = ['username','country_code','phone_number', 'password1', 'password2',
'full_name' ]
def clean_phone_number(self):
phone_number = self.data.get('phone_number')
print(phone_number)
if User.objects.filter(phone_number=phone_number).exists():
raise forms.ValidationError(
_("Another user with this phone number already exists"))
if len(phone_number) == 10 and phone_number.isdigit():
pass
else:
raise forms.ValidationError(
_("Invalid Phone Number"))
return phone_number
def save(self, *args, **kwargs):
print("saving")
user = super(RegisterForm, self).save(*args, **kwargs)
user.set_password(self.cleaned_data['password1'])
print('Saving user with country_code', user.country_code)
user.save()
return user
Views.py
class RegisterView(SuccessMessageMixin, FormView):
template_name = 'register-2.html'
form_class = RegisterForm
success_message = "One-Time password sent to your registered mobile number.\
The verification code is valid for 10 minutes."
def form_valid(self, form):
full_name=self.request.POST["full_name"]
user = form.save()
print(user.id)
username = self.request.POST['username']
password = self.request.POST['password1']
user = authenticate(username=username, password=password)
kwargs = {'user': user}
self.request.method = 'POST'
print("User created")
The print in clean_phone_number works however, save does not work
I had issue in the my form. One of the field was disabled and the value was not captured because of that.
However to identify that I used
def form_invalid(self,form):
# Add action to invalid form phase
messages.error(self.request, form.errors)
return self.render_to_response(self.get_context_data(form=form))

How to create user base on data from form?

forms.py
'''
class AddUserForm(forms.Form):
username = forms.CharField(label='Login', min_length=1)
password = forms.CharField(label='Password', widget=forms.PasswordInput)
repeat_password = forms.CharField(label='Repeat password', widget=forms.PasswordInput)
name = forms.CharField(label="First name", min_length=1, validators=[check_first_upper_letter_validator])
surname = forms.CharField(label="Last name",validators=[check_first_upper_letter_validator])
email = forms.CharField(validators=[EmailValidator()])
'''
views.py
'''
class AddUserView(View):
def get(self, request):
form = AddUserForm()
return render(request, 'exercises/form.html', {'form': form}) def post(self, request):
form = AddUserForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=...., email=....., password=....)
user.save()
return HttpResponse("OK")
else:
return render(request, 'exercises/form.html', {'form': form})
'''
How to get data from form for username, email etc.?
After django validates a form (which happens when you call form.is_valid()) a dictionary is added to your form called cleaned_data which allows you to access your form data.
So, after form.is_valid() in your view you can access the name entered by form.cleaned_data['name'], the email by form.cleaned_data['email'] and so on.

How to validate ModelForm with unique_together fields in Django?

How to validate the unique_together error and how to return the custom error message to the html through the view.py. Please help.
model.py:
class Pcq(models.Model):
product = models.ForeignKey(Product, null=False)
component = models.ForeignKey(Component, null=False)
quantity = models.IntegerField('Quantity', null=False)
class Meta:
unique_together = ("product", "component")
def __unicode__(self):
return self.product.productname
Form.py
class PcqForm(ModelForm):
class Meta:
model = Pcq
fields = ['component', 'quantity']
exclude = ['product']
Views.py
def pcq_add(request, product_id):
if request.method == 'POST':
form = PcqForm(request.POST or None)
if form.is_valid():
pcq = form.save(commit=False)
pcq.product_id = product_id
pcq.save()
form = PcqForm()
successmsg = "Component added successfully! Add another Component..."
return render(request, 'maps/pcq/pcq_add.html', {'form': form, 'product_id': product_id, 'successmsg': successmsg})
form = PcqForm()
return render(request, 'maps/pcq/pcq_add.html', {'form': form, 'product_id': product_id})
You need a custom clean function for the form
class PcqForm(ModelForm):
class Meta:
model = Pcq
fields = ['component', 'quantity']
exclude = ['product']
def clean(self):
cleaned_data = super(PcqForm, self).clean()
component = cleaned_data.get('component')
quantity = cleaned_data.get('quantity')
if component and quantity:
try:
Pcq.objects.get(
component=component,
quantity=quantity,
)
except Pcq.DoesNotExist:
# Yay
pass
else
raise forms.ValidationError(_("Error message goes here"))
UPDATE
Same concept as above but in the view.
def pcq_add(request, product_id):
if request.method == 'POST':
form = PcqForm(request.POST or None)
data = {
'form': form,
'product_id': product_id
}
if form.is_valid():
pcq = form.save(commit=False)
pcq.product_id = product_id
try:
pcq.save()
except IntegrityError:
# You'll need to check the exception that is raised
# Handle failed unique_together
pass
else:
form = PcqForm()
data['successmsg'] = (
"Component added successfully! Add another Component.")
else:
form = PcqForm()
data = {'form': form, 'product_id': product_id}
return render(request, 'maps/pcq/pcq_add.html', data)
Alternatively:
remove the exclude = ['product']
on GET pass product_id to the form form = PcqForm(initial_data={'product': product_id})
Use the form to validate unique_together (Not sure you even need a custom clean then)

Django KeyError at /register/

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