Django Forms: Validation message not showing - django

Can anyone spot what I'm doing wrong in the following example. Validating messages are not appearing in my template when incorrect details are entered such as a invalid email address. The template is loading and there are no errors.
I'm excepting validation messages to be printed on page, however for some reason this has suddenly stop working. As you can see from the code example below I'm passing the form in the context back to the template. this used to work and today just stopped.
view.py
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# If form has passed all validation checks then continue to save member.
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.save()
#member = User.get_profile()
#member.name = form.cleaned_data['name']
#member.save()
member = Member(
user=user,
name=form.cleaned_data['name']
)
member.save()
# Save is done redirect member to logged in page.
return HttpResponseRedirect('/profile')
else:
# If form is NOT valid then show the registration page again.
form = RegistrationForm()
context = {'form':form}
return render_to_response('pageRegistration.html', context,context_instance=RequestContext(request))
form.py
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'User Name'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
passwordConfirm = forms.CharField(label=(u'Confirm Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = Member
# Don't show user drop down.
exclude = ('user',)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError("Username already taken.")
def clean(self):
try:
cleaned_data = super(RegistrationForm, self).clean()
password = cleaned_data.get("password")
passwordConfirm = cleaned_data.get('passwordConfirm')
if password != passwordConfirm:
raise forms.ValidationError("Password does not match, try again.")
return cleaned_data
except:
raise forms.ValidationError("Error")
pageRegistration.html
<form action="" method="POST">
{% csrf_token %}
{% if forms.errors %}
<p>
correct some stuff
</p>
{% endif %}
{{form}}
<br>
<input type="submit" value="submit">
</form>

Since, the form is not validate in the else clause your form variable is overriden with a new form where it looses all of the errors
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# If form has passed all validation checks then continue to save member.
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.save()
#member = User.get_profile()
#member.name = form.cleaned_data['name']
#member.save()
member = Member(
user=user,
name=form.cleaned_data['name']
)
member.save()
# Save is done redirect member to logged in page.
return HttpResponseRedirect('/profile')
return render_to_response('pageRegistration.html', context,context_instance=RequestContext(request))

Updated for the CBV world.
This is what was causing the equivalent error for me:
class CreateView(generic.CreateView): # or generic.UpdateView
def get_context_data(self, **kwargs):
context_data = super(CreateView, self).get_context_data(**kwargs)
# context_data['form'] = self.form_class # << this was the problematic override

Perhaps the page is returning a new form every time it reloads. Check if the
context variable in views.py contains 'form' : form

Related

Django forms: Update a user's attributes without changing username

I'm trying to create a form that allows a user to update their username or avatar. The problem that I am running into is that if I update the profile picture without changing the username, the django form validation if form.is_valid() will recognize the form as invalid, since the username already exists in the database. I'm using an update view, though I'm not sure I've implemented it correctly.
When I try to update the avatar without changing the username, I get a page that says "Form is invalid" from the line: HttpResponse("Form is invalid"). Is there a workaround to remove the form validation? I have tried removing if form.is_valid(): but received the error 'User_form' object has no attribute 'cleaned_data'.
I feel like there has to be an easy way around this that I have not been able to find, as so many sites allow you to update only one attribute at a time.
Views.py
model = User
form = User_form
fields = ['username', 'avatar']
template_name_suffix = '_update_form'
def update_profile(request, user_id):
if request.method == "POST":
form = User_form(request.POST, request.FILES)
if form.is_valid():
user = User.objects.get(pk=user_id)
username = form.cleaned_data['username']
avatar = form.cleaned_data['avatar']
if username != user.username:
user.username = username
if avatar != user.avatar:
if avatar:
user.avatar = avatar
user.save()
return redirect('index')
else:
return HttpResponse("Form is invalid")
models.py
class User(AbstractUser):
followed_by = models.ManyToManyField("User", blank=True, related_name="following")
avatar = models.ImageField(upload_to='profilepics/', verbose_name='Avatar', null=True, blank=True)
class User_form(ModelForm):
class Meta:
model = User
fields = ['username', 'avatar']
user_update_form.html
<form action="/profile/{{user.id}}/update" method="post" enctype='multipart/form-data'>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
You are doing too much work yourself. Django's ModelForms can not only create data, but update data as well. You pass the instance through the instance=… parameter:
from django.shortcuts import get_object_or_404
def update_profile(request, user_id):
user = get_object_or_404(User, pk=user_id)
if request.method == 'POST':
form = User_form(request.POST, request.FILES, instance=user)
if form.is_valid():
form.save()
return redirect('index')
else:
return HttpResponse('Form is invalid')
else:
form = User_form(instance=user)
return render(request, 'some_template.html', {'form': form})
For uniqness checks, it will exclude the instance when checking if the username already exists. So one can change the username, given the new username of course does not yet exists.

Saving Django user forms without changing the password

I'm maintaining a Django application and have encountered a bug where if a user edits their profile then their password is corrupted; it seems that set_password is not being used and so the password is set to an unencrypted value which is hardcoded in the form. It's not clear how I could change the existing setup to get around this nuisance, and would welcome any suggestions. The update code looks like this:
#login_required
def profile(request):
user = request.user
profile, created = UserProfile.objects.get_or_create(user=user)
if request.method == 'POST':
userform = UserForm(request.POST, instance=user)
profileform = ProfileForm(request.POST, instance=profile)
if profileform.is_valid():
profileform.save()
if userform.is_valid():
userform.save()
return redirect('user_profile_page')
else:
profileform = ProfileForm(instance=profile)
userform = UserForm(instance=user)
render(request, 'profiles/edit_profile.html', {'profileform': profileform, 'userform': userform})
return render(request, 'profiles/edit_profile.html', {'profileform': profileform, 'userform': userform})
Then, the userform which is causing the problem contains this odd-looking code:
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('last_login', 'date_joined', 'is_active', 'is_superuser', 'is_staff')
username = forms.CharField(widget=forms.TextInput(attrs={'readonly': 'readonly'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'readonly': 'readonly', 'value': '00000000000000000'}))
I'm not really sure what the value attr in password is meant to be doing. Anyway, I tried to modify this by adding the following to the UserForm:
def save(self, commit=True):
user = super(UserForm, self).save(commit=False)
password = self.cleaned_data["password"]
if len(password) > 0 and password != '00000000000000000':
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
I had no luck with this either, and if I simply omit the password field from the userform or the relevant html then the form does not validate.
<form method="post" action="" class="wide">
{% csrf_token %}
.....
<label for="id_password">Password:</label>
{{ userform.password }}
Can anyone suggest how this might be cleaned up?
Use a separate form for editing the password and remove it from this one. Add password to the exclude list and remove the field declaration.

django modelformset_factory(User) provides two formsets

I have tried to use modelformset_factory(User) to create a form to add (and in next step edit) a user.
I'm confused, why it creates a form with my current user and an empty one for a new one?
Any Idea how i could remove the one with the current?
Here is my view.py code:
#login_required
def update_or_edit_user_profile(request, UserID = None, template_name='userprofile_form.html'):
#check when a userid is provided if its the personal or if the user is allowed to edit the profile
if UserID != None:
if (request.user.has_perm('change_user_profile') or request.user.pk == UserID):
pass
else:
raise PermissionDenied
# when user is allowed to continue:
UserFormSet = modelformset_factory(User)
if request.method == 'POST':
userformset = UserFormSet(request.POST, request.FILES)
if userformset.is_valid():
newUser=userformset.save()
else:
userformset = UserFormSet()
return render_to_response(template_name, {
"userformset": userformset,
})
and my template:
<form action="" method="post">{% csrf_token %}
{{ userformset.as_p }}
<input type="submit" value="Send message" />
</form>
You're confusing forms with formsets. A formset is a collection of forms, so Django is giving you exactly what you asked for. If you only want a single form, then that's what you should use:
class UserForm(forms.ModelForm):
class Meta:
model = User
def update_or_edit_user_profile...
user = User.objects.get(pk=UserID)
if request.method == 'POST':
form = UserForm(request.POST, instance=user)
if form.is_valid():
form.save()
return HttpResponseRedirect('/')
else:
form = UserForm(instance=User)
return render(request, template_name, {'form': form})

Django username already taken error

I have an form that allows a user to create a user account.The problem is , whenever a user submit a username that already been taken through the system . The form doesn't raise an error but it does raise an error when a field is missing. Can someone kindly help me
def Registration(request):
form = UserRegistration()
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.save()
return render(request,'choose.html',{'form':form})
return render(request, 'register.html', {'form': form},)
My forms.py
class UserRegistration(forms.Form):
username = forms.CharField()
email = forms.EmailField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
password = forms.CharField(
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")
user = User.objects.filter(username=username)
if user :
raise forms.ValidationError(
"That user is already taken , please select another ")
return cleaned_data
My template
<form method ="POST">
{% csrf_token %}
<span id="error">{{form.username.errors}}</span>
<span id="error2">{{form.email.errors}}</span>
<span id="error3">{{form.password.errors}}</span>
{{form.username}}
{{form.email}}
{{form.password}}
<input type = "submit" value= "save" id="box2"/>
</form>
You should use the exists[0] method:
user = User.objects.filter(username=username)
if user.exists():
raise forms.ValidationError("That user is already taken")
Edit:
Try using the clean_username method:
class UserRegistration(forms.Form):
....
def clean_username(self):
username = self.cleaned_data['username']
if User.objects.filter(username=username).exists():
raise forms.ValidationError("That user is already taken")
return username
You could add a Test to make sure it works:
from django.test import TestCase
class TestUniqueUsername(TestCase):
def test_unique_username(self):
User.objects.create(username='test', password='test', email='test#django.com')
form = UserCreationForm(data={'username': 'test'})
self.assertFalse(form.is_valid())
[0] https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.exists
Try this code
class UserRegistration(forms.Form):
username = forms.CharField()
email = forms.EmailField(error_messages={'required':'Error Missing Field , Please Fill this Field'})
password = forms.CharField(
widget=forms.PasswordInput(render_value=False)
)
def clean_username(self):
cleaned_data = self.cleaned_data
username = cleaned_data.get("username")
user = User.objects.filter(username=username)
if user.count() > 0:
raise forms.ValidationError("That user is already taken , please select another ")
return username
This will do the trick.

How to update User object without creating new one?

Following works fine in shell:
>>> from django.contrib.auth.models import User
>>> user=User.objects.get(pk=1)
>>> user.first_name = u'Some'
>>> user.last_name = u'Name'
>>> user.save()
>>> user.first_name
u'Some'
>>> user.last_name
u'Name'
Then I try to do the same with forms:
# forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name']
# views.py
def edit_names(request, template_name="registration/edit_names.html"):
if request.method == "POST":
form = UserForm(data=request.POST)
if form.is_valid():
user = form.save(commit=False)
user.save()
url = urlresolvers.reverse('my_account')
return HttpResponseRedirect(url)
else:
form = UserForm(instance=request.user)
page_title = _('Edit user names')
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
# edit_names.html
<form action="." method="post">{% csrf_token %}
<table>
{{ form.as_table }}
<tr><td colspan="2">
<input type="submit" />
</td></tr>
</table>
</form>
I open page in browser and see two fields First name and Last name. When I fill in the fields and submit the form I get the error:
Exception Type: IntegrityError
Exception Value: column username is not unique
I also tried to add ['username'] to fields list in UserForm. If I submit the form with my username (as request.user), the form displays errormessage:
User with this Username already exists.
If I change the username to some unique name, the new user with that username is being created.
The question is:
How can I update User object, not create new one?
Sorry for being so verbose, but I had hard search here and could not find the answer to my question.
BTW, these cases don't work for me:
Extending UserCreationForm to include email, first name, and last name
add field first_name and last_name in django-profile
How to create a UserProfile form in Django with first_name, last_name modifications?
EDIT:
As suggested #fceruti I just added on request.method == 'post' branch this:
form = UserForm(data=request.POST, instance=request.user)
Just add on request.method == 'post' branch this:
form = UserForm(data=request.POST, instance=request.user)
if request.method == "POST":
kwargs = { 'data' : request.POST }
try:
kwargs['instance'] = User.objects.get(username=request.POST['username'])
except:
pass
form = UserForm(kwargs**)
if form.is_valid():
user = form.save(commit=False)
...