django form is valid() fails - python

I am trying to create a registration form using django, when I submit my form the is valid() function fails and I am not sure why. I have my registration and login page all on one html page, although, I have called all the field names different names, eg login_username.
forms.py
class SignUpForm(forms.Form):
username = forms.CharField(label='Username', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Username'}))
conUsername = forms.CharField(label='Confirm Username', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Confirm Username'}))
firstName = forms.CharField(label='First Name', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Firstname'}))
lastName = forms.CharField(label='Last Name', max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter LastName'}))
email = forms.CharField(label='Email', max_length=220,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Enter Email','type':'email'}))
conEmail = forms.CharField(label='Confirm Email', max_length=220,widget=forms.TextInput(attrs={'class': 'form-control','placeholder':'Confirm Email','type':'email'}))
password = forms.CharField(label="Confirm Password", max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','type':'password','placeholder':'Enter Password'}))
conPassword = forms.CharField(label="Confirm Password", max_length=20,widget=forms.TextInput(attrs={'class': 'form-control','type':'password','placeholder':'Confirm Password'}))
views.py
def SignUp(request):
regForm = SignUpForm()
form = LoginForm()
if request.method == 'POST':
if regForm.is_valid():
username = regForm.cleaned_data('username')
print username
confirm_username = regForm.cleaned_data('conUsername')
first_name = regForm.cleaned_data('firstName')
last_name = regForm.cleaned_data('lastName')
email = regForm.cleaned_data('email')
confirm_email = regForm.cleaned_data('conEmail')
password = regForm.cleaned_data('password')
confirm_password = regForm.cleaned_data('conPassword')
#try:
#user = User.objects.get(username=request.POST['username'])
#return render(request, 'index.html',{'error_message':'username must be unique'})
#except User.DoesNotExist:
#user = User.objects.create_user(request.POST['username'], password=request.POST['password'])
#login(request, user)
#return render(request, 'index.html')
else:
return render(request,'index.html',{'username_error':'usernames didnt match','form':form,'regForm':regForm})
else:
return render(request, 'index.html',{'form':form,'regForm':regForm})
index.html
<form class="regForm" method="POST" action="{% url 'signup' %}">
{% csrf_token %}
{{username_error }}
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{regForm.error_message.username}}
{{ regForm.username }}
</div>
</div>
<div class="col-md-2 ">
<div class="form-group">
{{error_message.conUsername}}
{{ regForm.conUsername }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{ regForm.firstName }}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ regForm.lastName }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<div class="form-group">
{{ regForm.email }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<div class="form-group">
{{ regForm.conEmail }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-2 col-md-offset-8">
<div class="form-group">
{{ regForm.password }}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ regForm.conPassword }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-9">
<div class="form-group">
<button type="submit" id="regBtn" class="btn btn-default">Submit</button>
</div>
</div>
</div>
</form>

Right now your form is always empty and therefore invalid. You forgot to add the request POST content to the form.
def SignUp(request):
# ...
if request.method == 'POST':
regForm = SignupForm(request.POST) # form needs content
if regForm.is_valid():
# ...
If you get stuck when calling .is_valid(), you can print(regForm.errors) to see what's up.

You have two main problems. Firstly, you are never passing the POST data to the form, so it can never be valid.
Secondly, for some reason you are ignoring everything that the form could tell you about why it is not valid, and always returning "usernames didn't match". What's more, you're not even doing anything to compare usernames, so that error message will never be accurate.
You should rework your view to follow the pattern as described in the documentation:
def SignUp(request):
if request.method == 'POST':
regForm = SignUpForm(request.POST)
if regForm.is_valid():
...
return redirect(somewhere)
else:
regForm = SignUpForm()
return render(request, 'index.html', {'regForm':regForm})
and in your template make sure you include {{ form.errors }} to show what the validation failures are.

Related

submit button is not working in django form using crispy

I have a contact form in Django, and I use crispy in my template, but in both the Class base view and Function base view, my submit button is not working, and I have no errors.
here is my fbv code. I also tried it with cbv
my template is using jquery,bootstrap,moment.js
here is my code:
models.py
class ContactUs(models.Model):
fullname = models.CharField(max_length=150, verbose_name="Full Name")
email = models.EmailField(max_length=150, verbose_name="Email")
message = models.TextField(verbose_name="Message")
is_read = models.BooleanField(default=False)
class Meta:
verbose_name = "contact us"
verbose_name_plural = "Messages"
forms.py:
class CreateContactForm(forms.Form):
fullname = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "Full Name"}),
validators=[
validators.MaxLengthValidator(150,
"Your name should be less than 150 character")
],
)
email = forms.EmailField(widget=forms.EmailInput(attrs={"placeholder": "Email address"}),
validators=[
validators.MaxLengthValidator(150,
"Your email should be less than 150 character")
],
)
message = forms.CharField(widget=forms.Textarea(attrs={"placeholder": "Your Message"}))
views.py:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(fullname=fullname, email=email, message=message, is_read=False)
# todo : show user a success message
contact_form = CreateContactForm(request.POST or None)
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)
Template:
<form id="contact-form" class="contact-form" data-toggle="validator" novalidate="true" method="post" action="">
{% csrf_token %}
<div class="row">
<div class="form-group col-12 col-md-6">
{{ contact_form.fullname|as_crispy_field }} {% for error in contact_form.fullname.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-6">
{{ contact_form.email|as_crispy_field }} {% for error in contact_form.email.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-12">
{{ contact_form.message|as_crispy_field }} {% for error in contact_form.message.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 order-2 order-md-1 text-center text-md-left">
<div id="validator-contact" class="hidden"></div>
</div>
<div class="col-12 col-md-6 order-1 order-md-2 text-right">
<button type="submit" name="submit" class="btn"><i class="font-icon icon-send"></i> Send Message</button>
</div>
</div>
</form>
Try adding "save" to the submit button class.
Also your contact_page view does nothing after saving the contact data to the db. If you'll do a pop-up confirmation in JS you don't need to instantiate contact_form the second time. Or if you want to redirect the user:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(
fullname=fullname,
email=email,
message=message,
is_read=False
)
return redirect('some-view')
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)

Receiving an Error when a Form is submitted related to cleaned_data

I am trying to submit a Message form for my Django Project but I keep receiving an error:
AttributeError at /
'MessageForm' object has no attribute 'cleaned_data'
I am not sure what is the reason for getting this error although I revised the https://docs.djangoproject.com/en/3.1/topics/forms/
Here is my views.py
def home(request):
if request.method == 'POST': #Check Post
form = MessageForm(request.POST)
if form.is_valid():
data = MessageForm() #Create Relationship with Model
data.name= form.cleaned_data['name']
data.email= form.cleaned_data['email']
data.message= form.cleaned_data['message']
data.ip = request.META.get('REMOTE_ADDR')
data.save()
messages.success(request,'Your Message has been sent, Thank you!')
return HttpResponseRedirect('base:home')
template_name = 'base/home.html'
form = MessageForm()
----------------------other unrelated contexts--------------------
context = {
'form': form,
}
return render(request, template_name, context)
Here is the urls.py
urlpatterns = [
path('', views.home,name='home')
]
Here is the template.html
<form class="form" id="form" method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-6">
<div class="form-group">
<input name="name" id="form-name" type="text" placeholder="Your Name" class="form-control input" autocomplete="off"/>
<div id="name-error"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<input name="email" id="form-email" type="email" class="form-control input" placeholder="Your E-Mail" autocomplete="off">
<div id="email-error"></div>
</div>
</div>
</div>
<div class="form-group">
<textarea name="message" id="form-message" class="form-control input" rows="7" placeholder="Your Message here ..." autocomplete="off"></textarea>
<div id="message-error"></div>
</div>
<!-- Messages -->
{% if messages %}
{% for message in messages %}
<div class="container">
<div class=" alert alert-{{ message.tags }}">
{{ message }}
</div>
</div>
{% endfor %}
{% endif %}
<!-- Messages -->
<input id="form-submit" type="submit">
<div class="send-message" >
Send <i class="ni ni-send"></i>
</div>
</form>
You are constructing a new form, but that does not make much sense. Once your orignal form is validated, you can save that form, so:
def home(request):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
form.instance.ip = request.META.get('REMOTE_ADDR')
form.save()
messages.success(request,'Your Message has been sent, Thank you!')
return redirect('base:home')
# …

Pictures not saving in media folder

I noticed that when I upload a profile picture the picture is not being saved in my media directory.
I have manually created the folder and referenced it in settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
urls.py:
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
models.py:
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
...
class Mentor(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
linkedin = models.URLField(max_length=200,null=True,blank=True)
photo = models.ImageField(null=True, blank=True, upload_to='media')
forms.py
#basic form
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name','last_name','email')
# edit mentor profile
class MentorProfileForm(forms.ModelForm):
class Meta:
model = Mentor
fields = ('photo',)
and views.py:
def edit_user(request):
user = request.user
# form = MentorProfileForm(instance=user)
if request.method == 'POST':
form = UserForm(request.POST, request.FILES, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user)
if form.is_valid() and mentorform.is_valid():
form.save()
mentorform.save()
messages.success(request, ('Your profile was successfully updated!'))
return HttpResponseRedirect('%s' % (reverse('teachers:edit_user')))
else:
messages.error(request, ('Please correct the error below.'))
else:
form = UserForm(request.POST, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user)
return render(request, 'classroom/teachers/app-instructor-profile.html', {'form': form,
'mentor_form': mentorform})
EDIT
As requested here is the html template I am using to upload the picture and other profile info. I am convinced that the problem is with my html. I'm not sure what else I could be doing wrong
<form id="edit-mentor-profile" class="form-horizontal" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="photo" class="col-sm-2 control-label">Avatar</label>
<div class="col-md-6">
<div class="media v-middle">
<div class="media-left">
<div class="icon-block width-100 bg-grey-100">
<img id="image" style="width:99%;height:99%;">
</div>
</div>
<div class="media-body">
<input type="file" id="files" class="btn btn-white btn-sm paper-shadow relative" data-z="0.5" data-hover-z="1" data-animated/>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-md-2 control-label">Full Name</label>
<div class="col-md-8">
<div class="row">
<div class="col-md-6">
<div class="form-control-material">
{{ form.first_name }}
<label for="edit-mentor-profile-first_name"></label>
</div>
</div>
<div class="col-md-6">
<div class="form-control-material">
{{ form.last_name }}
<label for="edit-mentor-profile-last_name"></label>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="email" class="col-md-2 control-label">Email</label>
<div class="col-md-6">
<div class="form-control-material">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
{{ form.email }}
<label for="edit-mentor-profile-email"></label>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-6">
<div class="checkbox checkbox-success">
<input id="checkbox3" type="checkbox" checked="">
<label for="checkbox3">Subscribe to our Newsletter</label>
</div>
</div>
</div>
<div class="form-group margin-none">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary paper-shadow relative" data-z="0.5" data-hover-z="1" data-animated>Save Changes</button>
</div>
</div>
</form>
As #schwobaseggl said, file should be stored in /media/media folder. But there is another problem in your code, here:
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user) # <-- Here
Here it should be:
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user.mentor)
Because MentorProfileForm is using Mentor model, not User model. Also you need to fix the code for handling GET request:
def edit_user(request):
user = request.user
# form = MentorProfileForm(instance=user)
if request.method == 'POST':
form = UserForm(request.POST, request.FILES, instance=user)
mentorform = MentorProfileForm(request.POST, request.FILES, instance=user.mentor)
if form.is_valid() and mentorform.is_valid():
form.save()
mentorform.save()
messages.success(request, ('Your profile was successfully updated!'))
return HttpResponseRedirect('%s' % (reverse('teachers:edit_user')))
else:
messages.error(request, ('Please correct the error below.'))
else:
form = UserForm(instance=user) # <-- Here
mentorform = MentorProfileForm(instance=user.mentor) # <-- Here
return render(request, 'classroom/teachers/app-instructor-profile.html', {'form': form,
Please use below code in your html template. Where you are using form tag.
<form enctype="multipart/form-data" method="post">
--------- --------
---------Your code-------
</form>

Django validation error messages only showing in admin page

I have a SignUp form that interacts with Django's user model to create new users. If password fields match, the user is successfully created and logged in. If password fields do not match, the user is not created, so I guess validation is working. But somehow, a validation error message is not shown, the form page is just rendered again. When I go to Django's admin page, the error messages pop up there! Why is it not popping in my template?!
This is my form:
class SignUpForm(forms.ModelForm):
password = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'placeholder':'Password', 'class':'form-control', 'type':'password'}),)
password2 = forms.CharField(max_length=20, required=True, widget=forms.TextInput(attrs={'placeholder':'Confirm Password', 'class':'form-control', 'type':'password'}),)
class Meta:
model = User
widgets = {'first_name': forms.TextInput(attrs={'placeholder':'First Name', 'class':'form-control'}),
'last_name': forms.TextInput(attrs={'placeholder':'Last Name', 'class':'form-control'}),
'email': forms.TextInput(attrs={'placeholder':'Email', 'class':'form-control', 'type':'email'}),
'username': forms.TextInput(attrs={'placeholder':'Username', 'class':'form-control'}),
'password': forms.TextInput(attrs={'placeholder':'Password', 'class':'form-control', 'type':'password'})
}
fields = {'first_name', 'last_name', 'email', 'username', 'password'}
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
password = cleaned_data.get('password')
password2 = cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError('Passwords do not match!')
And this is my view:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
form.save()
user = authenticate(username=username, password=password)
login(request, user)
messages.add_message(request, messages.SUCCESS, 'Account created successfully!')
return HttpResponseRedirect('/')
else:
messages.add_message(request, messages.ERROR, "There's an error in the form! Please fill it again.")
return render(request, 'form/register.html', {'form': form})
else:
form = SignUpForm()
return render(request, 'form/register.html', {'form': form})
And this is my template:
<div class="login-box-body">
{% block login_form %}
<form method="POST">
{% csrf_token %}
{% if form.errors %}
{% for error in field.errors %}
<p class="login-box-msg" style="color: red;">{{ error }}</p>
{% endfor %}
{% endif %}
<div class="form-group has-feedback">
{{form.first_name}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.last_name}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.email}}
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.username}}
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.password}}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
{{form.password2}}
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8">
<button type="button" class="btn btn-default" onclick="window.location.href='{% url 'manager:login' %}'">Voltar</button>
</div>
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Criar Conta</button>
</div>
</div>
</form>
{% endblock login_form %}
What am I doing wrong?
Okay, I managed to work it out, at least as a temporary solution! Daniel was right, there was a typo in my template, but it was showing "_ all _" as the error message, not sure why.
Since the password fields were the only ones I was using raise forms.ValidationError function, then the error message was only to be shown in case the passwords wasn't matching.
So I just wrote the error message I wanted directly in my template! Like this:
<form method="POST">
{% csrf_token %}
{% if form.errors %}
<p class="login-box-msg" style="color: red; font-weight: bold;">Passwords do not match!</p>
{% endif %}
It doesn't work the way I wanted, but it does the job!

Sanic Form Validation Failing Silently

Hey guys I am using Sanic with WTForms and Sanic-WTF. I have this code for my SignUpForm:
class SignUpForm(SanicForm):
email = EmailField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(),
Length(min=3, max=25), EqualTo('confirm_password', message='Passwords must match.')])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired()])
I also have this as my validation for my validation in a Class Based View.
async def post(self, request):
form = SignUpForm(request)
email = form.email.data
print(email)
email_exists = await unique_db(email)
print(form.errors)
print ('Form validated: {}, Email Exists: {}'.format(form.validate_on_submit(), email_exists))
if form.validate_on_submit() and email_exists == False:
print('Validated')
await app.db.user_details.update_one({'user':'details'},{'$set': data}, upsert=True)
return json({'success':True})
return template('signup.html', form=form)
I have no idea what is going on. I have also tried doing form.validate()
My SignUp Form is
<form name="SignupForm" style="padding-top: 50px;" method="post">
{{ form.csrf_token }}
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10 col-sm-12">
<div class="card">
<div class="card-body">
<h3 class="card-title">Sign up</h3>
{{ macros.render_field(form.email, label_visible=true, placeholder='Email', type='email') }}
<small id="passwordHelpBlock" class="form-text text-muted">Your email must be in the form name#example.com</small>
{{ macros.render_field(form.password, label_visible=true, placeholder='Password', type='password') }}
{{ macros.render_field(form.confirm_password, label_visible=true, placeholder='Confirm Password', type='password') }}
<button type="submit" class="btn btn-success" id="login-submit-button">Submit</button>
</div>
<div class="card-footer text-muted text-center">
Already have an account? Log in
</div>
</div>
</div>
</div>
</form>
Ok so their seems to be a bug in SanicForm, because when I changed my SignUpForm class to inherit from Form (the generic WTForm form class) it worked fine.

Categories

Resources