Why django form post with errors updates instance - django

I have a standard user update form like
#login_required()
def personal(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
if user_form.is_valid():
user = user_form.save()
update_session_auth_hash(request, user)
messages.success(request, 'Your personal data has been changed successfully!')
return redirect('profile')
else:
user_form = UserForm(instance=request.user)
context = {
'form': user_form,
}
return render(request, 'personal.html', context)
The problem here is in the line user_form.is_valid(). It runs validation logic which collects an error when username is already taken by another user. In this case we have ValidationError raised but the instance in this form is updated nevertheless due to code in django's construct_instance function logic:
def construct_instance(form, instance, fields=None, exclude=None):
"""
Construct and return a model instance from the bound ``form``'s
``cleaned_data``, but do not save the returned instance to the database.
"""
...
f.save_form_data(instance, cleaned_data[f.name])
...
I found this behavior very strange. How can I avoid updating user's instance fields with wrong values if I need, say, display initial user's username on the top of my page?

Related

Is there a way to register new users with Django registration templates that would prevent them from logging in until admin has manually reviewed?

I'm working on login/registration views in Django in a project that requires that the admin manually reviews the application before the user can actually login...while saving the information they provided at the registration page.
In the past I didn't have projects that required the users be reviewed manually by the admins.
def register(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
new_user = form.save()
login(request, new_user)
return index(request)
else:
form = UserCreationForm()
return render(request, "registration/register.html", {"form": form})
This is what I would normally write...but even if I don't include the login(request, new_user), the new_user would be able to do so himself after the new_user is created...
I need to make sure they still can't login until the admin has manually reviewed his application to join.
Django has a semi built in way to do this. Use user.is_active, assuming that you are using the default authentication backend (you almost certainly are if you aren't sure what that is).
new_user.refresh_from_db()
new_user.is_active = False
new_user.save()
Just add these three lines after new_user = form.save()
def register(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
new_user = form.save()
new_user.refresh_from_db()
new_user.is_active = False
new_user.save()
return HttpRequest("Thank you for signing up. Your account is pending review.")
else:
form = UserCreationForm()
return render(request, "registration/register.html", {"form": form})
Administrators can login to the Admin site and manually approve the user by changing the is_active element.

AttributeError at /basic_app/register/ : 'tuple' object has no attribute 'get'

I know this question have been asked alot and most of the time its due to render or HttpResponse in the views.py, i double checked mine but the code looks good to me, dont know where the problem is.
This is a views.py file for a very basic django form but i can't get it to work
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data = request.POST)
profile_form = UserProfileInfoForm(data = request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_from.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit = False)
profile.user = user
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
registered = True
else:
return (user_form.errors,profile_form.errors)
else:
user_form = UserForm()
profile_form = UserProfileInfoForm()
return render(request,'basic_app/register.html',{'user_form': user_form,
'profile_form':profile_form,
'registered':registered})
You can not return (user_form.errors, profile_form.errors), since that is not a HttpResponse object. What response should the server return in that case.
Usually in case the form is invalid, the server will rerender the content. The form will, if you render it properly display the errors.
Note that in case the POST request was successful, you usually should redirect to implement the Post/Redirect/Get pattern [wiki]. You furthermore probably want to use a UserCreationForm [Django-doc]. This will set the password of the user in the correct way (with .set_password(..)), and run a password validator if you configured this.
You thus can rewrite your view as follows, but you probably should replace UserForm with UserCreationForm:
from django.shortcuts import redirect
def register(request):
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileInfoForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_from.save(commit=False)
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'profile_pic' in request.FILES:
profile.profile_pic = request.FILES['profile_pic']
profile.save()
return redirect('name-of-view')
else:
user_form = UserForm()
profile_form = UserProfileInfoForm()
return render(
request,
'basic_app/register.html',
{'user_form': user_form, 'profile_form':profile_form })

The view account.views.register didn't return an HttpResponse object

Good day everyone, i'm new to django, i'm working on a project were users can create accounts, i'm using the django registration model. Here's the problem,during registration, if the username the guest wants to use is taken or the passwords entered don't match, it gives this error 'The view account.views.register didn't return an HttpResponse object. It returned None instead.' instead of informing the guest about the errors.
views.py
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# # Set the chosen password
new_user.set_password(
user_form.cleaned_data['password'])
# Save the User object
new_user.save()
profile = Profile.objects.create(user=new_user)
return render(request, 'account/register_done.html', {'new_user': new_user})
else:
user_form = UserRegistrationForm()
return render(request, 'account/register.html', {'user_form': user_form})
As Selcuk suggested in the comment, add an else clause in your views as below,
from django.http import HttpResponse
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# # Set the chosen password
new_user.set_password(
user_form.cleaned_data['password'])
# Save the User object
new_user.save()
profile = Profile.objects.create(user=new_user)
return render(request, 'account/register_done.html', {'new_user': new_user})
else: # form is not valid
return HttpResponse("Form is not valid")
else:
user_form = UserRegistrationForm()
return render(request, 'account/register.html', {'user_form': user_form})

RelatedObjectDoesNOTExist-Edit profile

Django==1.10.5. I have a problem RelatedObjectDoesNotExist
Views.py:
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid():
# Create a new user object but avoid saving it yet
new_user = user_form.save(commit=False)
# Set the chosen password
new_user.set_password(user_form.cleaned_data['password'])
# Save the User object
new_user.save()
# Create the user profile
profile = Profile.objects.create(user=new_user)
return render(request,
'account/register_done.html',
{'new_user': new_user})
else:
user_form = UserRegistrationForm()
return render(request, 'account/register.html', {'user_form': user_form})
and
#login_required
def edit(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = ProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
else:
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=request.user.profile)
return render(request, 'account/edit.html', {'user_form': user_form,
'profile_form': profile_form})
The problem is that:
profile_form = ProfileEditForm(instance=request.user.profile)
I have similar experience working on this particular exercise.
The error is coming right from code below
Profile_form = ProfileForm(request.POST, instance=request.user.profile)
We are trying to get "request.user.profile" not realizing "User" in the model doesn't have a "profile" but a Profile has a"User" . Therefore a better way to get the "profile":
profile = Profile(user=request.user)
Hence your edit method should look close to this:
#login_required
def edit(request):
profile = Profile(user=request.user)
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,data=request.POST)
profile_form = ProfileEditForm(instance=profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.success(request, 'Error updating your profile')
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=profile)
return render(request,
'accounts/edit.html',
{'user_form': user_form,
'profile_form': profile_form})
Just to answer this question, this code is a snippet from the Django By Example book from the project Building a Social Website.
I encountered the same error when I clicked on the edit your profile link in the dashboard.
So, to solve this error, if you are logged in as a superuser, then go to the admin site of your project (url: localhost/admin/) and then under the Account heading, click on Profiles and click the Add profile link on the top right corner. Select the user from the dropdown, add the profile details and click save.
Now going back to the dashboard and clicking the edit your profile link should display the desired view.
I tried another alternative this scenario is that when we update our code we have some users that registered but not have a profile. I deleted the users and in admin and signed up with account it worked
but you will have a problem when logging with facebook

Set form 'author' field to logged in user before render

I want to set the default value of my forms 'author' field (models.ForeignKey(User)) to the currently logged in user. I want to do this before the entry is saved so when creating an entry the user does not have to select themselves in order for the form to validate.
I tried setting the value in my form init function, but there is not reference to the request object so it seems impossible?
I am not using the django admin panel for this application.
Dynamic initial values worked for me, for a default Django form view:
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm(initial={'author': request.user })
return render_to_response('contact.html', {
'form': form,
This sets the initial value in the author drop-down for an unbound form, the user could still change it whilst editing.
You can set the author attribute when you're processing the form in the view (note that in my example, the 'MyForm' class is a Model Form, and I exclude the 'author' field from the form):
def submit_form(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.save()
return http.HttpResponseRedirect('submitted/')
else:
form = MyForm()
context = Context({'title': 'Submit Form', 'form': form, 'user': request.user})
return render_to_response('form.html', context)
"Dynamic initial values"