I have the following functions to change a password and display the users profile, but upon submitting the form instead of being redirected to the 'profile/' page I get an error saying The view core.views.change_password didn't return an HttpResponse object. It returned None instead., why is this?
from django.contrib.auth.forms import UserChangeForm, PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
def change_password(request):
if request.method == "POST":
form = PasswordChangeForm(data= request.POST, user = request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user) #this function keeps the user logged in afte they change their password
# request.user could not have been passed in because that would pass in 'AnonymousUser', however
#form.user gets the user who was filling in the form and passes it to the function
return redirect('/profile')
else:
form = PasswordChangeForm(user = request.user)
args = {'form': form} # gives access to the form in the template
return render(request, 'core/change_password.html', args)
def view_profile(request):
args = {'user': request.user} #
return render(request, 'core/profile.html', args)
Note: The profile page does work on other parts of the site, for example after logging in the user is redirected to their profile page with no issue.
You should move the last two lines out of the else block. This way, you will return a response for POST requests when the form is not valid.
def change_password(request):
if request.method == "POST":
form = PasswordChangeForm(data= request.POST, user = request.user)
if form.is_valid():
...
return redirect('/profile')
else:
form = PasswordChangeForm(user = request.user)
args = {'form': form} # gives access to the form in the template
return render(request, 'core/change_password.html', args)
Related
I'm improving my English, be patient
My form is a ModelForm and all the necessary data is sent by the user, but I want dynamically set the field ["viagem"] with the last object in the queryset.
How to set a field after sending the data
def cadastro(request):
dono = Dono.objects.get(user=request.user)
if request.method == "POST":
form = VendaForm(dono, request.POST)
# Here I get the necessary data to call my qs
colocador_id = form["colocador"].value()
viagem = Colocador.objects.get(pk=colocador_id).viagem_set.last()
# I want something like this
form["viagem"] = viagem
if form.is_valid():
form.save()
else:
print('error')
print(form.errors)
else:
form = VendaForm(dono)
context = {"form": form, }
return render(request, 'dashboard/cadastro.html', context)
print(form.errors) => <ul class="errorlist"><li>viagem<ul class="errorlist"><li>This field is required</li></ul></li></ul>
Then you should not add this as a Form field. You thus exclude it from the fields in your ModelForm and work with:
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
#login_required
def cadastro(request):
dono = get_object_or_404(Dono, user=request.user)
if request.method == 'POST':
form = VendaForm(dono, request.POST)
if form.is_valid():
form.instance.viagem = form.cleaned_data['colocador'].viagem_set.last()
form.save()
else:
print('error')
print(form.errors)
else:
form = VendaForm(dono)
context = {'form': form, }
return render(request, 'dashboard/cadastro.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
def register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid() is True:
form.save()
#log the user in
return redirect('/account')
else:
form = UserCreationForm()
args = {'form': form}
return render(request, 'accounts/reg_form.html', args)
If i try to log in it seems that it doesn't think the data is valid and i don´t know why. It just cleans the registration fields and shows the registrationsite again. I´m using Django 2.1
What is the best way to show confirmation on step2.html in Django?
forms.py:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea())
views.py:
from django.views.generic import FormView
from .forms import ContactForm
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.http import HttpResponseRedirect
def step1(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
#save and cleared_form
return HttpResponseRedirect('/step2/')
else:
form = ContactForm()
return render(request, 'step1.html', {'form': form})
def step2(request):
ctx = { 'Test_1': 'email#email.com'}
return render(request, 'step2.html', ctx)
step2.html:
{{Test_1}}
On step 2 I want to show fields submitted on step 1, how to achieve that?
Good solution will be to show step2.html in step1 view when valid form is submitted, instead of redirecting user to step2. That way you will have access to your form data in view and template.
When submitting confirmation, values from step 1 can be passed by hidden fields or saved into session storage.
Example:
def step1(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
ctx = {'contact_data': form.cleaned_data}
return render(request, 'step2.html', ctx)
else:
form = ContactForm()
return render(request, 'step1.html', {'form': form})
You can save whole form data (cleaned_data) into session storage before redirection in step 1. That way you will be able to retrieve that data in step 2. Example:
def step1(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
#save and cleared_form
request.session.contact_form = form.cleaned_data
return HttpResponseRedirect('/step2/')
else:
form = ContactForm()
return render(request, 'step1.html', {'form': form})
def step2(request):
contact_data = request.session.get('contact_form', None)
if contact_data is None:
return HttpResponseRedirect('/step1/')
# someone is entering step 2 directly, without submitted form in step 1, we should redirect him back to step 1.
ctx = {'contact_data': contact_data}
return render(request, 'step2.html', ctx)
Consider using Form wizard. It will handle for you passing submitted data between steps (using cookies or session). All you need to do is: create 2 views, one with proper form, one with just some confirmation button and in template for step 2 retrieve all data from step 1.
Specifically, after authentication and redirect, request.user is an anonymous user.
login (view function)
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
#django.contrib.auth.login
Login(request, form.get_user())
str = reverse('cm_base.views.index')
return HttpResponseRedirect(str)
else:
# Their password / email combination must have been incorrect
pass
else:
form = LoginForm()
return render_to_response('cm_base/login.html',
{"DEBUG": True,
'form' : form
},
context_instance=RequestContext(request))
in the index view, I removed the login_required decorator and tested the request.user object
def index(request):
test = request.user.is_authenticated()
return render_to_response('cm_base/index.html',
{"DEBUG": True,
"user": request.user,},
context_instance=RequestContext(request))
Test returns false.
Fix
I ended up just calling the index view directly. I am still confused as to why the user object was lost when I called HttpResponseRedirect.
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST) # Not shown in this example
if form.is_valid():
Login(request, form.get_user())
str = reverse('cm_base.views.index')
return index(request)
else:
# Their password / email combination must have been incorrect
pass
else:
form = LoginForm()
A lot of things going on here that shouldn't be. First, you don't need to pass request.user, its available by default as long as you are using RequestContext, which you are.
Login() this method, what exactly is it doing? Django provides a built-in login method that you should be using if you are using the default authentication backend.
You are also not checking if a user is enabled or disabled.
Here is a different version of your code, adapted from the example in the documentation:
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
def login_view(request):
form = LoginForm(request.POST or {})
ctx = {'form': form}
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username, password)
if not user:
ctx['errors'] = 'Invalid Login'
return render(request, 'login.html', ctx)
if not user.is_active:
ctx['errors'] = 'User is locked'
return render(request, 'login.html', ctx)
login(request, user)
return redirect('home')
else:
return render(request, 'login.html', ctx)
What auth backend are you using? If it is something other than the ModelBackend make sure your get_user method is correct. It sounds as if the auth middleware is sending a different identifier (like the pk instead of a username) than the one you are looking for in your get_user method.
This was the fix
<link rel="icon" href="{{ STATIC_URL }}img/favicon.ico" />
This file was missing from the static directory. The resulting 404 was breaking the user session.
I've this:
def profile(request, username):
if request.method == 'POST':
if request.user.is_authenticated():
new_message = Message(author = request.user)
form = MessagesForm(request.POST, instance = new_message)
else:
form = MessagesForm(request.POST)
if form.is_valid():
form.save()
else:
to_user = User.objects.get(username = username)
form = MessagesForm(initial = {'user': to_user.pk})
return render(request, "profile.html", {
'username': username,
'form': form,
'messages': messages,
})
This form submit a message and return the same page. My problem is that after the submit I see again my field filled with my information. How to clear it after the submit?
After saving form instead of showing post dict assign the empty form
form = EmployeeForm()
if request.method == "POST":
pDict = request.POST.copy()
form = EmployeeForm(pDict) #if not valid shows error with previous post values in corresponding field
if form.is_valid():
form.save()
form = EmployeeForm() # show empty form no need to give HttpResponseRedirect()
It's standard to redirect after form submission to prevent duplicates.
Just return a redirect to your form on success.
if form.is_valid():
form.save()
return http.HttpResponseRedirect('')
after save() you can return 'form' key with MessagesForm(request.GET) value.
return render(request, "profile.html", {
'username': username,
'form': MessagesForm(request.GET),
'messages': messages,
})
Usually you can initialize the same empty form after you have saved datas:
if request.method == "POST":
rf = RegistrationForm(request.POST)
if rf.is_valid():
print 'Saving datas..'
#logic to save datas
rf = PreRegistrationForm()
return render_to_response('registration/confirmation_required.html', {'settings': settings}, context_instance=RequestContext(request))
Try using HttpResponseRedirect('/') instead of HttpResponseRedirect('') in #Karthikkumar's answer, especially if your home view is an empty path, for instance you have in your urls.py file:
urlpatterns = [path('',views.home_view),]
I had similar issues as those discussed above where HttpResponseRedirect('') directed me to a blank page. Let me know if adding the slash works for you!
You can use this:
Sometimes you can use this idea take attrs={ "autocomplete":"off"} for each inputs.
You can redirect back to the initial post
post_url = request.build_absolute_uri(post.get_absolute_url())
return HttpResponseRedirect(post_url)
please note that 'post' is an instance of the model created
I am hoping you have already defined a logic for GET methods. In the case that you have, all you can do is simply add return request.META['HTTP_REFERER'] at the end.
See what I mean:
def profile(request, username):
if request.method == 'POST':
if request.user.is_authenticated():
new_message = Message(author = request.user)
form = MessagesForm(request.POST, instance = new_message)
else:
form = MessagesForm(request.POST)
if form.is_valid():
form.save()
else:
to_user = User.objects.get(username = username)
form = MessagesForm(initial = {'user': to_user.pk})
return HttpResponseRedirect(request.META['HTTP_REFERER'])
This should work, I just tested it.
**Maybe I am late but for Django 4.x developers can use: **
from .forms import TodoForm
from django.contrib import messages
from django.http import HttpResponseRedirect
def mytodos(request):
form = TodoForm()
if request.method =='POST':
form=TodoForm(request.POST)
if form.is_valid:
form.save()
messages.success(request,'Task saved successfully')
return HttpResponseRedirect('/todo/')
mycontext={'form':form}
return render(request, 'todo/todo.html',mycontext)
in my urls.py: , i have set path('todo/',views.mytodo, name='todolist')
As you can see, after saving form, mycode will redirect to /todo/ which is automatically refreshed after every submit and a fresh form comes again everytime. If you are a good django dev, you will understand what I did. Make sure to reply if you have any queries .Thanks :)
When we reload the page (F5 or ctrl+shift+R), it submits the previously sent data. so instead of refreshing, we will directly hit the url using return HttpResponseRedirect('/posts/')
This way it will show the page with empty form (now even if you refresh it will only show data, won't submit it previous data again)
from django.shortcuts import render, HttpResponseRedirect
from django.views import View
from .models import Post
from .forms import PostForm
class PostListView(View):
def post(self, request, *args, **kwargs):
posts = Post.objects.filter(author=request.user).order_by('-created_on')
form = PostForm(request.POST)
if form.is_valid():
new_post = form.save(commit=False)
new_post.author = request.user
new_post.save()
return HttpResponseRedirect('/posts/')
context = {
'post_list': posts,
'form': form
}
return render(request, 'social/post_list.html', context)