I am new to Django. I am trying to make a simple form to match the password. However, when I enter different passwords and press the Save button I get a cleared form instead of showing the validation error.
Here newuser.html:
{% block content %}
<form method="POST">
{% csrf_token %}
<table>
{{frmNewUser.as_table}}
{% for error in frmNewUser.password.errors %} {% comment %} I tried frmNewUser.non_field_errors too {% endcomment %}
<p>{{error}}</p>
{% endfor %}
</table>
<input type="submit" name="Save" value="Save" colspan=2>
</form>
{% endblock content %}
Here forms.py:
class NewUserFrom(forms.Form):
username = forms.CharField(max_length=50, widget=forms.TextInput)
password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(label="Confirm password", widget=forms.PasswordInput)
name = forms.CharField(max_length=50, widget=forms.TextInput)
email = forms.EmailField(max_length=50, widget=forms.EmailInput)
def clean(self):
cleaned_data = super().clean()
pwd = cleaned_data.get('password')
cof_pwd = cleaned_data.get('confirm_password')
if pwd and cof_pwd:
if pwd != cof_pwd:
raise forms.ValidationError('Password is not match.')
return super().clean()
Here views.py:
from django.shortcuts import render
from django.http import HttpResponse, request
from django.db import connection
from django.contrib.auth.decorators import login_required
import pyodbc
from .forms import NewUserFrom
def newUser(request):
form = NewUserFrom(request.POST)
if not form.is_valid():
return render(request,'login/newuser.html', {'frmNewUser':NewUserFrom})
return render(request, "login/welcome.html")
Try following this article, it helped when i had a similar problem
in the newUser function
def newUser(request):
form = NewUserFrom(request.POST)
if not form.is_valid():
return render(request,'login/newuser.html', {'frmNewUser':NewUserFrom})
return render(request, "login/welcome.html")
the return value in the if statement should be changed from {'frmNewUser':NewUserFrom}) to {'frmNewUser':form})
I have an issue with my code in the sense that when a student registers, a double instance of the student is created. I don't know what's the problem with these block of code. Please help out,also I don't know how to make a link between a teacher and a student so as to allow the teacher to add results for students.
views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm,UserUpdateForm ,InformationUpdateForm,InformationForm
def home(request):
return render(request, 'student/home.html')
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form=InformationForm(request.POST)
# ####and a_form.is_valid()
if form.is_valid() and a_form.is_valid():
user = form.save()
# form.save()
#finally this get links the models, forms and views for user input and all information is registered
information = a_form.save()
# a_form.save()
user.information.majors=a_form.cleaned_data.get('majors')
user.information.department=a_form.cleaned_data.get('department')
user.information.nationality=a_form.cleaned_data.get('nationality')
user.information.date_of_birth=a_form.cleaned_data.get('date_of_birth')
user.information.passport_number=a_form.cleaned_data.get('passport_number')
user.information.phone_number=a_form.cleaned_data.get('phone_number')
user.information.sex=a_form.cleaned_data.get('sex')
user.save()
information.save()
# for this type user input is for for username,last,first and email is registered
# form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('login')
else:
form = UserRegisterForm()
a_form = InformationForm()
context={'form':form,'a_form':a_form }#,'a_form':a_form
return render(request, 'student/register.html', context)
#login_required
def profile(request):
return render(request, 'student/profile.html')#,context
#login_required
def profile_update(request):
if request.method == 'POST':
u_form=UserUpdateForm(request.POST,instance=request.user)
i_form=InformationUpdateForm(request.POST,request.FILES,instance=request.user.information)
if u_form.is_valid() and i_form.is_valid():
u_form.save()
i_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
else:
u_form=UserUpdateForm(instance=request.user)
i_form=InformationUpdateForm(instance=request.user.information)
context={'u_form': u_form,
'i_form':i_form}
return render(request, 'student/profile_update.html',context)
models.py
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
# CHOICES=[('M','Male'),
# ('F','Female')]
class Information(models.Model):
M='Male'
F='Female'
SELECT_GENDER_CHOICE=[(M, 'Male'),
(F, 'Female')]
########################################################
B='Bachelors'
Ma='Masters'
P='PhD'
SELECT_DEGREE_CHOICE=[(B, 'Bachelors'),
(Ma, 'Masters'),(P, 'PhD')]
#########################################################
Y1='1 year'
Y2='2 year'
Y3='3 year'
Y4='4 year'
Y5='5 year'
SELECT_YEARS_CHOICE=[(Y1, '1 year'),(Y2, '2 year'),(Y3, '3 year'),(Y4, '4 year'),(Y5, '5 year')]
user = models.OneToOneField(User,null=True,on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='student')
nationality=models.CharField(max_length=120,blank=False)
sex=models.CharField(max_length=8,choices=SELECT_GENDER_CHOICE,default=M)
department=models.CharField(max_length=120,blank=False)
years=models.CharField(max_length=120,blank=False,choices=SELECT_YEARS_CHOICE,default=Y1,null=True)
degree=models.CharField(max_length=120,blank=False,choices=SELECT_DEGREE_CHOICE,null=True)
majors=models.CharField(max_length=500,blank=False)
phone_number=models.CharField(max_length=12,blank=False)
passport_number=models.CharField(max_length=50,blank=False)#unique=True)
date_of_birth=models.CharField(max_length=10,blank=False)
report=models.FileField(default='StudentResults/DEFAULT_SHEET.xlsx',upload_to='StudentResults',max_length=500,blank=True)#,null=True
reg_no=models.CharField(max_length=10,null=True,unique=True)
def __str__(self):
return f'{self.passport_number} Information'
def save(self,*args, **kwargs):
super().save(*args, **kwargs)
img=Image.open(self.image.path)
if img.height>300 or img.width>300:
output_size=(300,300)
img.thumbnail(output_size)
img.save(self.image.path)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Information
# CHOICES=[('M','Male'),
# ('F','Female')]
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'Email'}))
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username'}))
first_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'First name'}))
last_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Last name'}))
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Confirm'}))
class Meta:
model = User
fields = ['username','first_name','last_name', 'email', 'password1', 'password2']
class InformationForm(forms.ModelForm):
#sex=forms.ChoiceField(choices=CHOICES)
department = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Department'}))
majors = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Majors'}))
nationality = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nationality'}))
date_of_birth = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Date of birth'}))
passport_number = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Passport number'}))
phone_number = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Phone number'}))
class Meta:
model=Information
fields=['department','majors','degree','years','nationality','date_of_birth','passport_number','phone_number','sex']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['email']
# def email(self):
# email = self.cleaned_data.get("email")#this gets the default title but does not override the required field
# #you can have multiple nested if else/elif statements. You can use this for email validation
# if not ".com" in email:
# raise forms.ValidationError("This is not a email")
# else:
# return email
class InformationUpdateForm(forms.ModelForm):
class Meta:
model=Information
fields=['phone_number']
signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Information
#receiver(post_save,sender=User)
def create_information(sender,instance,created,**kwargs):
if created:
Information.objects.create(user=instance)
#receiver(post_save,sender=User)
def save_information(sender,instance,**kwargs):
instance.information.save()
student-profile-page
{% extends "student/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.information.image.url }}">
<div class="media-body">
<p class="text-secondary">Username: {{ user.username }}</p>
<p class="text-secondary">First Name: {{ user.first_name }}</p>
<p class="text-secondary">Last Name: {{ user.last_name }}</p>
<p class="text-secondary">Email: {{ user.email }}</p>
<p class="text-secondary">Passport Number: {{ user.information.passport_number }}</p>
<p class="text-secondary">Date of Birth: {{ user.information.date_of_birth }}</p>
<p class="text-secondary">Sex: {{ user.information.sex }}</p>
<p class="text-secondary">Phone Number: {{ user.information.phone_number }}</p>
<p class="text-secondary">Nationality: {{ user.information.nationality }}</p>
<p class="text-secondary">Majors: {{ user.information.majors }}</p>
<p class="text-secondary">Depatrment: {{ user.information.department }}</p>
<p class="text-secondary">Results: {{ user.information.result }}</p>
<p class="text-secondary">Years: {{ user.information.years }}</p>
<p class="text-secondary">Degree: {{ user.information.degree }}</p>
<a class="btn btn-outline-info" href="{{ user.information.report.url}}">Download your Report</a>
</div>
</div>
{% comment %} <form method="POST">
{% csrf_token %}
<fieldset class="form-group" enctype="multipart/form-data">
<legend class="border-bottom mb-4">Profile Info</legend>
{{ i_form|crispy }}
{{ u_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div> {% endcomment %}
{% endblock content %}
That is because you are saving a_form.save() then again saving user.information.save(). You need to change the code like this:
user = form.save()
information = a_form.save(commit=False)
information.user = user
information.save()
messages.success(request, 'Your account has been created! You are now able to log in')
return redirect('login')
You can remove the rest of the code regarding user.information and remove the signals as well. You do not need signals to create Information instance because you have forms to do that.
You are getting double instance of user because of create_information signal.
user = form.save() in following code will save a User instance.
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form =InformationForm(request.POST)
if form.is_valid() and a_form.is_valid():
# form.save() creates a user, and triggers create_information signal
user = form.save()
information = a_form.save()
Now, you have a signal create_information, which is triggered after a User instance is saved (this signal is a post_save singal).
Your user = form.save() will create a user, and will triggers create_information signal.
#receiver(post_save,sender=User)
def create_information(sender,instance,created,**kwargs):
if created:
Information.objects.create(user=instance)
This save another instance of Information, and since Information model has OneToOne mapping to User, another User instance is also saved.
Side note: You have three Information instances saved as well. One created by create_information signal, one by save_information signal, and third by a_form.save() method. This number can be more if cyclic signals are triggered, but not sure about that, so you'll have to check that by yourself.
Solution:
Firstly, get rid of all singals.
Secondly, add User to Information instance before saving it.
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form =InformationForm(request.POST)
if form.is_valid() and a_form.is_valid():
user = form.save()
information = a_form.save(commit=False)
information.user = user
information.save()
I am doing a user registration function, this is views
from django.http import HttpResponseGone
from .forms import RegisterForms
from django.shortcuts import render
def register(request):
if request.method == 'POST':
user_forms = RegisterForms(request.POST)
if user_forms.is_valid():
new_userform = user_forms.save(commit=False)
new_userform.set_password(user_forms.cleaned_data['password'])
new_userform.save()
return HttpResponseGone('注册成功')
else:
return HttpResponseGone('注册失败')
else:
user_forms = RegisterForms()
return render(request,'account/register.html',{'form':user_forms})
this is forms
from django import forms
from django.contrib.auth.models import User
class RegisterForms(forms.ModelForm):
password = forms.CharField(label='Password',widget=forms.PasswordInput)
password2 = forms.CharField(label='password again',widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username','email')
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('密码输入不一致,请从新输入')
else:
return cd['password']
this is html
<p>欢迎注册</p>
<form action="." method="post">
{% csrf_token %}
<p>username {{ form.username }}</p>
<p>email {{ form.email }}</p>
<p>password {{ form.password }}</p>
<p>password again {{ form.password2 }}</p>
<input type="submit" value="register">
</form>
I found that if I change the name of the clean_password2 method in the views file to clean_password, I can not get the value of password2 in the form
This is the wrong message[enter image description here][4]
My English is not very good I hope someone can help me Thank Thank Thank
from django import forms
from django.contrib.auth.models import User
class RegisterForms(forms.ModelForm):
password = forms.CharField(label='Password',widget=forms.PasswordInput)
password2 = forms.CharField(label='password again',widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username','email','password','password2')
def clean(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('密码输入不一致,请从新输入')
else:
return cd
In short use clean method in such conditions.
Everytime I submit my form on '/signup' view, form.validate_on_submit() in my views.py throws the error below:
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given
The stack trace is pretty long and I don't see anything immediately obvious. I have no idea why it is doing this. I followed the Flask-WTF docs for validating forms.
EDIT: Here is the stack trace I am seeing.
views.py
from myapp import app
from flask import render_template, redirect
from forms import RegistrationForm
#app.route('/', methods=['POST', 'GET'])
#app.route('/signup', methods=['POST', 'GET'])
def signup():
form = RegistrationForm()
if form.validate_on_submit():
# Redirect to Dash Board
return redirect('/dashboard')
return render_template("signup.html", form=form)
#app.route('/login')
def login():
return "<h1>Login</h1>"
#app.route('/dashboard')
def dashboard():
return "<h1>Dashboard</h1>"
forms.py
from flask_wtf import FlaskForm
from wtforms import TextField, PasswordField
from wtforms.validators import InputRequired, Email, Length
class RegistrationForm(FlaskForm):
username = TextField('username', validators=[InputRequired(), Length(min=4, max=30)])
email = TextField('email', validators=[InputRequired(), Email, Length(max=25)])
password = PasswordField('password', validators=[InputRequired(), Length(min=8, max=80)])
class LoginForm(FlaskForm):
username = TextField('username', validators=[InputRequired(), Length(min=4, max=30)])
password = PasswordField('password', validators=[InputRequired(), Length(min=8, max=80)])
signup.html
{% extends "base.html" %}
{% block content %}
<h1>Sign Up</h1>
<form method="POST" action="/signup">
{{ form.hidden_tag() }}
<p>Username:</p>
{{ form.username() }}
<p>Email:</p>
{{ form.email() }}
<p>Password:</p>
{{ form.password() }}
<br/>
<br/>
<button type="Submit" value="submit" name="submit">Submit</button>
</form>
{% endblock %}
I figured it out! In forms.py, my RegistrationForm's email attribute should read:
email = TextField('email', validators=[InputRequired(), Email(), Length(max=25)])
I forgot the darn parenthesis for the Email parameter.
Could you review my code for improvement? Essentially, it works but it isn't user friendly. For example,(1) If the user puts in an invalid field, it doesn't tell them what field is invalid. (2) If a user tries to register (sign up) with an existing username, there is no way the user can distinguishes that error, specifically. Or if a user mis-type password confirm, the user won't know that mistake either. (3) Also, if the user produces an input error(s), the sign up page blanks out all the field and so the user has to re-enter in all the info. As you can imagine, that could be very frustrating for that user.
I tried to see if form.error_messages might help the user, the error_messages is useless.
How would you improve the code so that (1), (2), (3) is not a nuisance for the user? And one more thing, just curious about how you would change the css? I noticed that most professional website sign-up page highlight the input box that was invalid. I am clueless on how to apply changes to css for {{form|as_bootstrap}}
Many thanks for your help!
form.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True,help_text="Email field is required.")
firstname = forms.CharField(max_length=50, required=False, help_text="Optional. Can fill in later.")
lastname = forms.CharField(max_length=50, required=False, help_text="Optional. Can fill in later.")
class Meta:
model = User
fields = (
'username',
'email',
'password1',
'password2',
'firstname',
'lastname'
)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
user.firstname = self.cleaned_data["firstname"]
user.lastname = self.cleaned_data["lastname"]
if commit:
user.save()
return user
views.py
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.context_processors import csrf
from forms import MyRegistrationForm
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/account/register_success')
else:
form = MyRegistrationForm()
args = {}
args.update(csrf(request))
args['form']= form
print form.errors #this line doesn't print anything
return render_to_response('register.html', args)
else:
return HttpResponseRedirect('/')
def register_success(request):
return render_to_response('register_success.html')
register.html
{% extends 'base.html' %}
{% load bootstrap_toolkit %}
{
{% block title %}
<title>Register</title>
{% endblock %}
<body>
{% block content %}
<div class="col-sm-9 col-sm-offset-3 col-md-6 col-md-offset-2 main">
<h2>Register</h2>
{% if form.error_messages %}
<p class="error"> {{ form.error_messages }}.</p>
{% endif %}
<form class="form-signup" role="form" action="/account/register/" method="post"> {% csrf_token %}
{{ form|as_bootstrap }}
<input type="submit" value="Register" class="btn btn-primary"/>
</form>
</div>
{% endblock %}
</body>