I have a Django form consisting of a email and name field. I want to validate the name to have more than 8 characters. I have used the following code. But it is not working.
class SignUpForm(forms.ModelForm):
class Meta:
model=SignUp
fields=('email','name')
def emailValidation(self):
name=self.cleaned_data.get('name')
if len(name) <=8:
raise forms.ValidationError("name cannot be less than 8")
models.py
class SignUp(models.Model):
name=models.CharField(max_length=200)
email=models.EmailField()
timestamp=models.DateTimeField(auto_now_add=True, auto_now=False)
updated=models.DateTimeField(auto_now=True,auto_now_add=False)
def __unicode__(self):
return self.name
views.py
def home(request):
form=SignUpForm(request.POST or None)
if form.is_valid():
instance=form.save(commit=False)
instance.save()
print instance.timestamp
return render(request, 'home.html',{'form':form})
In your SignUpForm, in the function emailValidation, you haven't returned 'name'. Also a major mistake is that you have to name the function clean_(field_name) and NOT emailValidation.
This should do it I guess:
class SignUpForm(forms.ModelForm):
class Meta:
model=SignUp
fields=('email','name')
def clean_name(self):
name=self.cleaned_data.get('name')
if len(name) <=8:
raise forms.ValidationError("name cannot be less than 8")
return name
You need to use correct name for your validation method. Django forms will call methods with the format clean_<fieldname>.
Also you seem to be confused about which field you are validating; your email validation method should be called clean_email and should access the email value via form.cleaned_data['email'], and the name one should be called clean_name and access form.cleaned_data['name'].
Something like this may give you some guidance.
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
firstname = forms.CharField(label="First Name")
lastname = forms.CharField(label="Last Name")
phone = forms.CharField(label="Phone")
email = forms.EmailField(label="Email")
password1 = forms.CharField(label="Password")
password2 = forms.CharField(label="Password (again)")
min_password_length = 8
class Meta:
model = User
fields = ['firstname', 'lastname', 'phone', 'email', 'password1', 'password2']
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError(u'Email "%s" is already in use! Please log in or use another email!' % email)
return email
def clean_password1(self):
" Minimum length "
password1 = self.cleaned_data.get('password1', '')
if len(password1) < self.min_password_length:
raise forms.ValidationError("Password must have at least %i characters" % self.min_password_length)
else:
return password1
def clean(self):
"""
Verifies that the values entered into the password fields match
NOTE: Errors here will appear in ``non_field_errors()`` because it applies to more than one field.
"""
cleaned_data = super(RegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords didn't match. Please try again.")
return self.cleaned_data
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
Related
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))
So I'm making a custom user model. This is what I'am following Here. I have been pretty much following the tutorial but still I cant make it done.
Error: RegisterForm() missing 1 required positional argument: 'request'.
here's my code.
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class LoginForm(forms.ModelForm):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', 'password',)
widgets = {
'email' : forms.EmailInput(
attrs={'class':'form-control', 'place_holder': '', }),
'password' : forms.PasswordInput(
attrs={'class':'form-control' }),
}
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class UserManager(BaseUserManager):
def create_user(self, email, full_name, password=None, is_staff=False, is_active=True, is_admin=False):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not full_name:
raise ValueError('Users must have an full name')
if not password:
raise ValueError('Users must have a password')
user = self.model(
email=self.normalize_email(email),
)
user.full_name = full_name
user.set_password(password)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.save(using=self._db)
return user
def create_staffuser(self, email, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, full_name, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.model(
email=self.normalize_email(email)
)
user.full_name = full_name
user.set_password(password)
user.full_name = full_name
user.staff = True
user.admin = True
user.save(using=self._db)
return user
# Create your models here.
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, null=True, blank=True)
active = models.BooleanField(default=True) # to login
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
created_date = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name'] # Email & Password are required by default.
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
return self.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
class Account_type(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
account_type = models.ForeignKey(Account_type, on_delete=models.CASCADE)
register.html
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def RegisterForm(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
The view logic is simple as you can see. Just saving up the request into the database. The tutorial itself did not tell anything about the view for login and register.
So, What am I doing wrong here.
Thank you
The problem is that your view RegisterForm has the same name as your form, hence if you call RegisterForm in your view, it will resolve to the view function, and make a recursive call.
Normally (top-level) functions are written in snake_case, hence you can rewrite it to register_form, or even better register (since it is not a form at all):
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-view-name')
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
Normally a successful POST request results in a redirect to implement the Post/Redirect/Get pattern [wiki]. So I strongly advise you to use redirect(..) [Django-doc] and replace some-view-name with the name of a view to which you want to redirect.
class CustomAccount(models.Model):
user = models.OneToOneField("auth.User")
role = models.CharField(max_length = 50, default = 'student', choices=APPROVAL_CHOICES)
balance = models.FloatField( default = 0 )
timezone = models.CharField(max_length = 200)
def __str__(self):
return self.user.username +" ["+ self.role + "]"
class CustomAccountForm(forms.ModelForm):
username = forms.CharField(max_length=30 )
email = forms.EmailField(max_length=255 )
password1 = forms.CharField(label= "Password",widget=forms.PasswordInput())
password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput , help_text="Enter the same password as above, for verification.")
def save(self, commit= True):
user = User.objects.create_user(username = self.cleaned_data['username'], email = self.cleaned_data['email'] , password = self.cleaned_data['password1'])
user.save()
self.user = user
return super(CustomAccountForm, self).save(commit=commit)
def clean_username(self):
username = self.cleaned_data["username"]
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError("A user with that username already exists.")
def clean_password2(self):
password1 = self.cleaned_data.get("password1", "")
password2 = self.cleaned_data["password2"]
if password1 != password2:
raise forms.ValidationError("The two password fields didn't match.")
return password2
def clean_email(self):
email = self.cleaned_data["email"]
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError("A user with that emailaddress already exists.")
class Meta:
model = CustomAccount
exclude = ['balance','user']
I want to create Custom account in Django Admin section using single form which has fields of auth.User and CustomAccount Model. I have getting error IntegrityError at /admin/mylogin/customaccount/add/
NOT NULL constraint failed: mylogin_customaccount.user_id
Since you are getting a not null error, I think you need to specify that the field is not required. Here is an example from one of my apps. This says that the form field is not required.
class arunModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
myuser = kwargs.pop('user', None)
super(arunModelForm, self).__init__(*args, **kwargs)
self.fields['nanoadded'].required = False
self.fields['response'].required = False
I also include this in my models so that my model fields can be null, like this:
class arun(models.Model):
auser = models.CharField(max_length=50, null=True)
adate = models.DateField(null=True)
atime = models.TimeField(null=True)
If I still get not null errors after I do both of these things, I fill the field with a place holder value to allow me to further investigate the problem.
You have removed the user from the form and in the save method, you have assigned self.user in save method. So when saving the form, the user attribute is not used for CustomAccountForm and the user field for CustomAccount is None.
Your save method should look like:
def save(self, commit= True):
user = User.objects.create_user(username =self.cleaned_data['username'], email = self.cleaned_data['email'] , password = self.cleaned_data['password1'])
user.save()
obj = super(CustomAccountForm, self).save(commit=False)
obj.user = user
obj.save()
i am using custom user authentication model which uses an email address as the username and creates the user but even if password1 is different than password2 the registration completes successfully. i am unable to debug the problem.
here is models.py file:
class UserManager(auth_models.BaseUserManager):
def create_user(self, email, first_name, last_name, password):
"""
Creates and saves a user with given email,
first name, last name and password.
"""
if not email:
raise ValueError("users must have an email address")
user = self.model(
email=UserManager.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(self._db)
return user
def create_superuser(self, email, first_name, last_name, password):
"""
Creates and saves a super_user with given email,
first name, last name and password.
"""
if not email:
raise ValueError("users must have an email address")
user = self.model(
email=UserManager.normalize_email(email),
first_name=first_name,
last_name=last_name,
)
user.is_admin = True
user.set_password(password)
user.save(self._db)
return user
class User(auth_models.AbstractBaseUser):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
joined_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', ]
def get_full_name(self):
return self.first_name + " " + self.last_name
def get_short_name(self):
return self.first_name
def __str__(self):
return self.get_full_name() + ", email= " + self.email
#property
def is_staff(self):
return self.is_admin
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
class Meta:
verbose_name_plural = "users"
admin.py
class UserCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='password', widget=forms.PasswordInput)
password2 = forms.CharField(label='confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
def clean_password(self):
"""
check that the two password entries match
"""
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match")
return password2
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""
A form for updating users. includes all the fields
on the user, but replaces the password field with
the admin's password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'password', 'is_active', 'is_admin')
def clean_password(self):
"""
Regardless of what the user provides, return the initial value.
This is done here, rather than on the field, because the field
does not have access to the initial value.
"""
return self.initial["password"]
views.py
def register(request):
args = {}
args.update(csrf(request))
if request.method == 'POST':
form = UserCreationForm(request.POST)
args['form'] = form
if form.is_valid():
form.save()
return HttpResponseRedirect('/home/')
else:
args['form'] = UserCreationForm()
return render_to_response('authentication/signup.html', args, context_instance=RequestContext(request))
Try moving the password comparison logic present in the clean_password() function to a clean() function in the UserCreationForm.
The clean_fieldname() function should operate on the field fieldname and not any other field.
Also, when fields validation depends on each other then the best place to place the validation logic is inside the clean() method.
From Django docs:
We are performing validation on more than one field at a time, so the
form’s clean() method is a good spot to do this.
By the time the form’s clean() method is called, all the individual
field clean methods will have been run (the previous two sections), so
self.cleaned_data will be populated with any data that has survived so
far. So you also need to remember to allow for the fact that the
fields you are wanting to validate might not have survived the initial
individual field checks.
Code:
class UserCreationForm(forms.ModelForm):
...
def clean(self):
cleaned_data = super(UserCreationForm, self).clean()
password1 = cleaned_data.get("password1")
password2 = cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match")
return cleaned_data
The problem is, you doesn't has a 'password' field,
you need change the method name to, clean_password1 or clean_password2.
the method you created clean_password, will never be called
because there is no field called password
def clean_password1(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("passwords don't match"")
return password1
I'm attempting to determine if a user on my site is an adult by using his birthday and today's date.
I have a boolean attribute in my user called adult and I attempt to set it in the following way
from datetime import date
...
def set_adult(self):
today = date.today()
age = today.year - self.date_of_birth.year - ((today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day))
if age > 18:
self.adult = True
else:
self.adult = False
When registering a user, I have a field for adding a birthday
class MyRegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
email = forms.EmailField(widget=forms.EmailInput,label="Email")
date_of_birth = forms.DateField(widget=forms.DateInput(format='%m/%d/%Y'), label="Date of birth (MM/DD/YYYY)")
gender = forms.ChoiceField(widget=RadioSelect, choices=GENDER_CHOICES)
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
class Meta:
model = MyUser
fields = ['email', 'date_of_birth', 'gender', 'password1', 'password2']
def clean(self):
"""
Verifies that the values entered into the password fields match
NOTE: Errors here will appear in ``non_field_errors()`` because it applies to more than one field.
"""
cleaned_data = super(MyRegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords don't match. Please enter both fields again.")
return self.cleaned_data
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
user.set_adult # NOT WORKING
if commit:
user.save()
return user
When I check my admin page after adding an "adult birthday", the result is always false.
Am I making a mistake in my form or in my set_adult method?
user.set_adult # NOT WORKING
You are missing () in function call:
user.set_adult()