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].
Related
This is my view.py file under my project folder.
When I add a value in ToDo list it raises this error?
The view my_day.views.index didn't return an HttpResponse object. It returned None instead.
views.py
from django.shortcuts import render, redirect
from .models import List
from .form import ListForm
from django.contrib import messages
# Create your views here.
def index(request):
if request.method == "POST":
form = ListForm(request.POST or None)
if form.is_valid():
form.save()
all_items = List.objects.all
messages.success(request, ('Task Added'))
return render(request, 'index.html', {'all_items': all_items})
else:
all_items = List.objects.all
return render(request, 'index.html', {'all_items': all_items})
In your view, you have 3 possible outcomes based on the if conditions but only 2 of them returns a HttpResonse object. More specifically, the if form.is_valid() only returns a HttpResponse object if this condition passes. If it doesn't, it will return None (basically nothing) because there is no else condition or other fallback.
You need to add an else condition to the if form.is_valid(). More so, you should implement another approach than to serve content on a POST request. As WillemVanOnsem have commented, check out the Post/Redirect/Get pattern. I have replaced the return render(...) instances where needed to achieve this, but will need some tweaking to work, for instance replace the view name (should be defined in your urls.py file).
def index(request):
if request.method == "POST":
form = ListForm(request.POST or None)
if form.is_valid():
form.save()
all_items = List.objects.all
messages.success(request, ('Task Added'))
# Replaced the render(...) with a redirect instead.
# Replace "index" with the name of the view (if not index)
return HttpResponseRedirect(reverse("index"))
else:
# Added fallback if the form.is_valid() didn't pass
messages.failure(request, ('Failed when saving task'))
return render(request, 'index.html', {'all_items': all_items})
else:
all_items = List.objects.all
return render(request, 'index.html', {'all_items': all_items})
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)
def group_display(request, group_id):
groups = Groups.objects.get(id=group_id)
username = UserInfo.objects.get(owner = request.user)
form = membership_form()
template = 'groups.html'
if request.method == 'POST':
form = membership_form(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.name = username
post.group = groups
post.save()
context = {
'form':form,
}
return render(request, template, context)
The problem is that every time I reload page a new row is added to membership model. Seems like the page is loads as request.POST. is there any way i can insert the data only on button click?
After a successful POST request, it is best to return a redirect. This prevents the post request from being processed again if the page is refreshed. You can redirect to the current url if you want.
from django.shortcuts import redirect
def group_display(request, group_id):
...
if request.method == 'POST':
form = membership_form(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.name = username
post.group = groups
post.save()
return redirect('/success-url/')
...
There are two things you can do:
Redirect after a successful POST.
Check to make sure there isn't a registration for that user.
Here is a view that takes care of both:
from django.shortcuts import get_object_or_404, redirect
def group_display(request, group_id):
groups = get_object_or_404(Groups, id=group_id)
username = get_object_or_404(UserInfo, owner=request.user)
if username.membership_set.exists():
# This user is already enrolled
return redirect('/')
form = membership_form(request.POST or {})
template = 'groups.html'
context = {'form': form}
if form.is_valid():
post = form.save(commit=False)
post.name = username
post.group = groups
post.save()
return redirect('/')
return render(request, template, context)
You'll have to adjust username.membership_set.exists based on your own models.
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.
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)