Related
I'm trying to reuse a code for registration form from my older project. The problem is that Django says that UserCreationForm hasn't attribute clean_password1.
Do you know where is the problem? I see that there is not such attribute in UserCreationForm but it worked before.
What should I do to make it work?
EDIT: It's because it calls super(...).clean_password1 which isn't in super class. So I've tried to put there super(...).cleaned_data.get("password1"), but it raises error that cleaned_data isn't there (in superclass).
class UserProfileCreationForm(UserCreationForm):
username = forms.CharField(label="Username", max_length=40, min_length=5)
email = forms.EmailField(label="Email address", max_length=40)
first_name = forms.CharField(label='First name', max_length=40, required=False)
last_name = forms.CharField(label='Last name', max_length=40, required=False)
password1 = forms.CharField(label="Password", widget=forms.PasswordInput, min_length=5)
password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput)
class Meta():
model = UserProfile
fields = (
'username', 'email', 'type_of_user', 'first_name', 'last_name', 'password1', 'password2','IBAN',
)
def clean_password1(self):
password = self.cleaned_data.get('password1')
if len(password) < 8:
raise ValidationError('Password has to be of size at least 8 characters')
return super(UserProfileCreationForm, self).clean_password1()
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Password mismatch")
return password2
def save(self, commit=True):
try:
with transaction.atomic():
user = User(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
email=self.cleaned_data['email'])
user.save()
user.set_password(self.cleaned_data["password1"])
user_profile = UserProfile(user=user,
IBAN=self.cleaned_data['IBAN'],
type_of_user=self.cleaned_data['type_of_user']
)
user_profile.save()
except:
raise #TODO: HANDLE THE EXCEPTION
return user
You can safely remove clean_password2 - Django already validates if the passwords match (I assume you're using the current version for your new project). As for clean_password1 I'd recommend to remove it too and read documentation on password validation (new in Django 1.9).
There's no reason to call super inside a clean_field method; the field doesn't exist on the base class, so neither does the clean_field.
I am creating a form for a custom user type. But each time I submit the form to test it, it returns an error that says the unicode object has no attribute get error.
forms.py:
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
class Meta:
model = Student
fields = ('firstname', 'lastname', 'email', 'password1', 'password2', 'is_second_year')
def clean(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(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
models.py:
class StudentManager(BaseUserManager):
def create_user(self, firstname, lastname, email, is_second_year, password, is_officer=False, hours=0, points=0):
if not email:
raise ValueError("Student must have an email address.")
newStudent = self.model(
email = self.normalize_email(email),
firstname=firstname,
lastname=lastname,
is_officer=is_officer,
is_second_year=is_second_year,
hours=hours,
points=points
)
newStudent.set_password(password)
user.save(using=self.db)
return newStudent
def create_superuser(self, firstname, lastname, email, password, is_second_year, is_officer=True, hours=0, points=0):
newSuperStudent = self.create_user(
email = self.normalize_email(email),
firstname=firstname,
lastname=lastname,
is_officer=is_officer,
is_second_year=is_second_year,
hours=hours,
points=points,
password=password
)
newSuperStudent.is_admin = True
newSuperStudent.save(using=self.db)
return newSuperStudent
class Student(AbstractBaseUser):
firstname = models.CharField(verbose_name="First Name", max_length=30, default="")
lastname = models.CharField(verbose_name="Last Name", max_length=30, default="")
email = models.EmailField(
verbose_name='Email Address',
max_length=255,
unique=True,
default=''
)
is_officer = models.BooleanField(default=False)
is_second_year = models.BooleanField(verbose_name="Check this box if this is your second year in NHS")
hours = models.DecimalField(max_digits=5, decimal_places=2)
points = models.DecimalField(max_digits=3, decimal_places=1)
USERNAME_FIELD = 'email'
def __unicode__(self):
return self.username
views.py:
def sign_up(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = RegistrationForm(request.POST)
# check whether it's valid:
if form.is_valid():
print "money"
form.save()
# redirect to a new URL:
return HttpResponseRedirect('/sign_up_success/')
# if a GET (or any other method) we'll create a blank form
args = {}
args.update(csrf(request))
args['form'] = RegistrationForm()
return render_to_response('events/sign_up.html', args)
Error Location within the .is_valid() method:
field_value = self.cleaned_data.get(field, None)
My guess is that for some reason, the cleaned_data attribute of my form is a unicode object rather than a dictionary. But I have no clue why this is so!
clean must return the full cleaned_data dictionary, not a single string field.
I am using Django 1.8.After following tutorials of how to customize user model I decided to make an app using customized user model. My CustomUser model looks like -
class CustomUser(AbstractBaseUser):
first_name = models.CharField(max_length=100,blank=True)
last_name = models.CharField(max_length=100,blank=True)
college = models.CharField(max_length=200,blank=True)
email = models.EmailField(unique=True,blank=False)
date_joined = models.DateTimeField(_('date joined'), default=datetime.now())
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name']
objects = CustomUserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_absolute_url(self):
return "/users/%s/" % urlquote(self.email)
def get_full_name(self):
"""
Returns the first name plus the last name , with a space in between
"""
full_name = '%s %s' % (self.first_name,self.last_name)
return full_name.strip()
My CustomUserManager class is this (though not important to mention here) -
class CustomUserManager(BaseUserManager):
def _create_user(self,email,password,is_staff,is_superuser,**extra_fields):
"""
Creates and saves a User with the given email and password
"""
t = datetime.now()
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email,is_staff=is_staff,is_active=True,is_superuser=is_superuser,
last_login=t,date_joined=t,**extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self,email,password=None,**extra_fields):
return self._create_user(email,password,False,False,**extra_fields)
def create_superuser(self,email,password=None,**extra_fields):
print "Inside Superuser"
return self._create_user(email,password,True,True,**extra_fields)
I have added the relevant settings - AUTH_USER_MODEL and AUTHENTICATION_BACKENDS to the settings.py file.
Most importantly my custom registration form looks like this -
class CustomUserCreationForm(UserCreationForm):
"""
A form that creates a user, with no privileges, from the given email and password
"""
def __init__(self,*args,**kargs):
super(CustomUserCreationForm,self).__init__(*args,**kargs)
#print self.fields
del self.fields['username']
class Meta:
model = CustomUser
fields = ('email',)
I have mentioned here that my model will be CustomUser.As you can see that my custom form inherits from in-built UserCreation form. For the convenience I am also posting here UserCreationFrom class -
class UserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and
password.
"""
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
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."))
class Meta:
model = User
fields = ("username",)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
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
I have some doubts here.UserCreationForm has model set to User which is default User model(from django.contrib.auth.models import User);
but in my CustomForm's meta class I have mentioned model equal to my CustomUser.
When I print the fields returned by UserCreationForm it gives - username,password1,password2.Presence of 'username' field is the proof that UserCreationForm used 'User' model and added 'username' field which subsequently I deleted in my custom form.
I have also added 'email' to the fields in my custom form but Email option is not rendering in my registration page.Is what I am doing the right way to create Custom Registration forms?
If not then what should be done to render email field in my custom registration form.
from .models import CustomUser
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(label="Password", widget=forms.PasswordInput)
password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput)
class Meta:
model = CustomUserModel
# Note - include all *required* CustomUser fields here,
# but don't need to include password1 and password2 as they are
# already included since they are defined above.
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:
msg = "Passwords don't match"
raise forms.ValidationError("Password mismatch")
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
Source:
Django 1.5: UserCreationForm & Custom Auth Model
I am using django 1.7 with mongoengine. I have created a class Projects :
class Projects(Document):
user = ReferenceField(User, reverse_delete_rule=CASCADE)
p_name = StringField(max_length=70, required=True)
author = StringField(max_length=70, required=True)
url = StringField(max_length=200, required=True)
short_discription = StringField(max_length=100, required=True)
long_discription = StringField()
logo_url = StringField(max_length=200, required=False)
logo = ImageField(size=(250, 250, True))
tags = TaggableManager()
def __unicode__(self):
return self.p_name
def save(self, *args, **kwargs):
self.p_name = self.p_name
return super(Projects, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('view_project', args=[self.p_name])
def get_edit_url(self):
return reverse('update', args=[self.id])
def get_delete_url(self):
return reverse('delete', args=[self.id])
and i am referencing and storing user in my mongodb through my views :
class new_project(CreateView):
model = Projects
form_class = NewProjectForm
success_url = reverse_lazy('registered')
def get_template_names(self):
return["new_project.html"]
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super(new_project, self).form_valid(form)
and mongodb JSON format looks like this :
"user" : ObjectId("54db3e5d7818f4253e5da0db"),
I want to to create user profile where they can see their all projects, for that i created a view :
class UserProjectsListView(ListView):
model = Projects
context_object_name = "project"
def get_template_names(self):
return ["view_user.html"]
def get_queryset(self):
return self.model.objects.filter(user=self.kwargs['pk'])
and my urls.py :
url(r'^new_project/', new_project.as_view(),name='new_project'),
url(r'^project/(?P<pk>[\w\d]+)', view_project.as_view(), name='view_project'),
url(r'^user/(?P<pk>[\w\d]+)/$', UserProjectsListView.as_view(), name='detail'),
The problem with this is that i have to use the object id only in my url, but want to use username instead. Because on the template it renders only username not the object id.
Does anyone know how to use username in urls instead of object id, because rendering object id on template would not be good for security purpose also.
my user creation form :
class UserCreationForm(forms.Form):
error_messages = {
'duplicate_username': _("A user with that username already exists."),
'duplicate_email': _("A user with that email already exists."),
'password_mismatch': _("The two password fields didn't match."),
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.#+-]+$',
help_text=_("Required. 30 characters or fewer. Letters, digits and "
"#/./+/-/_ only."),
error_messages={
'invalid': _("This value may contain only letters, numbers and "
"#/./+/-/_ characters.")})
email = forms.EmailField(label=_("Email"), max_length=254,
help_text=_("Required valid email. 254 characters or fewer."),
error_messages={
'invalid': _("This value may contain only valid email address.")})
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 clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError(
self.error_messages['duplicate_username'],
code='duplicate_username',
)
def clean_email(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
email = self.cleaned_data["email"]
try:
User._default_manager.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(
self.error_messages['duplicate_email'],
code='duplicate_email',
)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
def save(self):
user = User._default_manager.create_user(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'],
password=self.cleaned_data["password1"])
return user
I also want to get data from three tables and i have used dev instead of class:
def UserProjectsListView(request, pk):
return render_to_response('view_user.html', {
'tuorial' : Tutorial.objects.filter(user=pk),
'question' : Question.objects.filter(user=pk),
'project': Project.objects.filter(user=pk),
})
P.S. Thanks in advance.
If MongoEngine can't simulate joins, it is very simple to do this in two separate queries:
def get_queryset(self):
user = User.objects.get(username=self.kwargs['username'])
return self.model.objects(user=user.id)
I am using Django 1.3/Python 2.7.
My application is using django.contrib.auth for User management. For the main user registration I have a form which checks if the 'email' has already been registered. So it makes sure all email fields are unique.
But it happens that some admins use the django admin interface to add users, and end up adding duplicate accounts with the same email.
For this purpose I have created a NewUserCreationForm, where I've duplicated the django.contrib.auth.UserCreationForm and added an 'email' field to it.
class NewUserCreationForm(forms.ModelForm):
"""
A form that creates a user, with no privileges, from the given username and password.
"""
username = forms.RegexField(label=_("Username"), max_length=30, regex=r'^[\w.#+-]+$',
help_text = _("Required. 30 characters or fewer. Letters, digits and #/./+/-/_ only."),
error_messages = {'invalid': _("This value may contain only letters, numbers and #/./+/-/_ characters.")})
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."))
email = forms.EmailField(label=_("Email"), max_length=75)
class Meta:
model = User
fields = ("username", "email")
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 save(self, commit=True):
user = super(NewUserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.email = self.email
if commit:
user.save()
return user
class CustomUserAdmin(UserAdmin):
add_form = NewUserCreationForm
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
But this code isn't working. I can see the form rendering, but with no email field, just the Username, password1 and password2 fields.
what is it that I am missing here?
You are missing ... UserAdmin.add_fieldsets, e.g.:
class CustomUserAdmin(UserAdmin):
add_form = NewUserCreationForm
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2', 'email')}
),
)