I have got a modal contact form. The form works fine, but the page reload resubmits previously entered values.
view.py
...
if request.POST:
form = ContactForm(request.POST)
if form.is_valid():
entry = form.save()
form = ContactForm()
c.update(locals())
return render(request, 'template.html', c )
...
template.html
<form action="." method="post" id="contact-form">
...
</form>
I tried to clear the form in the GET request. Form fields are cleared, but this does not prevent submission on the page reload.
else: #request.GET
form = ContactForm()
c.update(locals())
return render(request, 'template.html', c )
I have seen many examples suggesting a redirect. I do understand this approach, but in case of a modal form I would like to avoid a redirect.
How to prevent modal form re-submissions? Is the redirect really the only way?
Solution seems very simple:
Replaced this line...
return render(request, 'template.html', c )
... with the one below:
return HttpResponseRedirect(request.path_info)
Related
I need a call a form on an HTML template where the user posts data which saves to model
The code is running without any errors
But the html page display only title and button
No text input fields
I have a form which is to be displayed on a html page so the user can input data and it saves the data into the model.I am not getting any errors while executing th code but the template does not display the form it just shows the title and submit button
def boqmodel1(request):
form = boqform(request.POST)
if form.is_valid():
obj=form.save(commit=False)
obj.save()
context = {'form': form}
return render(request, 'create.html', context)
else:
context = {'error': 'The post has been successfully created.
Please enter boq'}
return render(request, 'create.html', context)
MyTemplate
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create boq"/>
</form>
MY Url
urlpatterns = [
url(r'^create/', views.boqmodel1, name='boqmodel1'),
path('', views.boq, name='boq'),
]
First of all, your first request, without submitting form is GET. When you submit a form you send POST.
The form is not displaying, because your form is not valid in the first place. Your function should look like this:
def boqmodel1(request):
context = {}
if request.method == "GET":
form = boqform()
context["form"] = form
# if you post a form do all the saving
if request.method == "POST":
form = boqform(request.POST)
context = {'form': form}
if form.is_valid():
obj=form.save()
return render(request, 'create.html', context)
else:
context["errors"] = form.errors
return render(request, 'create.html', context)
If method is GET init your form and pass it to your context, so you can display it on frontend.
If method is POST, init your form with your data from frontend (request.POST), check if the form is valid. If it is valid - save it. If it is not valid, return your errors and display them as you wish.
After user submits I redirect back to the same page with the users submitted data in the form. I can see the data POST and then immediately followed by a GET of the same page in Firefox 36.0.4 desktop, Chrome 41.0.2272 desktop, Opera 10.0 iPhone 5, Chrome 41.0.2272 iPhone 5. However, only the Chrome on mobile causes a "Confirm Resubmit" on refresh and also doesn't load all the js again. Is there a fix for this problem?
Here is my minimal simple view.
def workout(request):
form = WorkoutInfoForm(request.POST or None)
if form.is_valid():
form.save()
post = request.POST.copy()
request.session['_old_post'] = post
return redirect(reverse("workout.views.workout"))
if not request.POST:
old_post = request.session.get('_old_post')
form = WorkoutInfoForm(old_post or None)
return render_to_response("workout/track_workout.html",
locals(),
context_instance=RequestContext(request))
And my form start in my template
<form method='POST' action='' class="form-horizontal" role="form"> {% csrf_token %}
If the form is valid your code works as expected. The described problem occures only in case of invalid form. You can try something like
def workout(request):
form = WorkoutInfoForm(request.POST or None)
if request.POST:
post = request.POST.copy()
request.session['_old_post'] = post
if form.is_valid():
form.save()
return redirect(reverse("workout.views.workout"))
else:
old_post = request.session.get('_old_post')
form = WorkoutInfoForm(old_post or None)
return render_to_response("workout/track_workout.html",
locals(),
context_instance=RequestContext(request))
First the code.
The ModelForm (im1 and im2 are models.ImageField):
class TestForm(forms.ModelForm):
checkme = forms.BooleanField(required=True)
class Meta:
model = UserProfile
fields = ('im1', 'im2')
The view:
def test(request):
profile = request.user.get_profile()
form = TestForm(instance=profile)
if request.method == "POST":
form = TestForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
return render(request, 'test.html', {'form':form})
The template:
<html>
<head>
<title>Test</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" />
</form>
</body>
</html>
The problems:
If im1 contains a valid image, and I check the clear checkbox next to it but don't check checkme and submit, the form comes back with an error saying that checkme is required. Although the form returns with the error, it appears as if im1 has been cleared. In reality it has not because if I reload the form im1 shows back up with its file and clear checkbox.
My question is how can I fix this? Is it something I am doing or is this something to do with django?
Django is acting exactly as it should.
If the request is a POST request, then your form is bound to the data from request.POST and request.FILES. instance=profile is simply telling the form what particular object to save to if all validation passes. Even if your form isn't valid, it's still bound to the data with the cleared image, and that's what you're passing to render().
Firstly, you shouldn't be creating the first bound form if the request method is POST:
def test(request):
profile = request.user.get_profile()
if request.method == "POST":
form = TestForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
else:
form = TestForm(instance=profile)
return render(request, 'test.html', {'form':form})
Secondly, why do you want your user to do the same exact action twice if they did indeed want to delete an image but simply missed another checkbox?
If you really need Django to act this way, I would do one of two things. Either create a bound form from an instance of UserProfile and pass both the non-valid form and the newly created form to the template and use the non-valid form for displaying the errors and the other one for displaying the rest of the form:
def test(request):
profile = request.user.get_profile()
if request.method == "POST":
errors_form = TestForm(request.POST, request.FILES, instance=profile)
if errors_form.is_valid():
errors_form.save()
form = errors_form
else:
form = TestForm(instance=profile)
return render(request, 'test.html', {'form':form, 'errors_form': errors_form})
else:
form = TestForm(instance=profile)
return render(request, 'test.html', {'form':form})
OR I'd do the same thing but save the errors from the non-valid form to the newly created form so you don't end up with renders() all over the place:
def test(request):
profile = request.user.get_profile()
if request.method == "POST":
errors_form = TestForm(request.POST, request.FILES, instance=profile)
if errors_form.is_valid():
errors_form.save()
form = errors_form
else:
form = TestForm(instance=profile)
#this is left up to you to implement, but you'd do something like
#form.errors = errors_form.errors
#and also iterate through every form attribute.errors and assign it to
#errors_form attribute.errors etc...
else:
form = TestForm(instance=profile)
return render(request, 'test.html', {'form':form})
Both aren't very elegant solutions and I'm not positive the second one will even work as expected without some more hacks since I'm not completely familiar with the Django Forms implementation.
I don't see that doing this is worth it. As I stated before, you're just creating more work for your user...
i've a problem with django views. I have a URL /signup.html that have a view and display a form. The action of this form points to /account/create so when everything it's ok i do a redirect to congrats page, but when the form submitted it's invalid, i need to back to the last url with a dictionary of errors but when i do render_to_response the url in the address bar it's account/create and should /signup.html.
Here is the code:
def signup(request):
return render_to_response('main/signup.html' , {} , context_instance=RequestContext(request))
def create_account(request):
if request.method == 'POST':
form = FastSignupForm(request.POST)
if form.is_valid():
new_user = form.save()
return redirect('/account/congratulations' , {} , context_instance=RequestContext(request))
else:
form = FastSignupForm();
return render_to_response('main/signup.html', {'form':form} , context_instance=RequestContext(request))
def congrats(request):
return render_to_response('main/congrats.html', {}, context_instance=RequestContext(request))
What i'm doing wrong ?
EDIT:
If i post over the same url (signup.html), when a i reload the page i've multiple post submits and i want to prevent this.
Why not post to the same URL (signup.html) then only redirect when successful?
I'm confused as to why you need to go to /account/create. Can't you just do this:
views.py
def signup(request):
if request.method == 'POST':
form = FastSignupForm(request.POST)
if form.is_valid():
new_user = form.save()
return redirect('/account/congratulations' , {} ,
context_instance=RequestContext(request))
else:
form = FastSignupForm();
return render_to_response('main/signup.html', {'form':form} ,
context_instance=RequestContext(request))
def congrats(request):
return render_to_response('main/congrats.html', {},
context_instance=RequestContext(request))
main/signup.html
...
<form method="post" action=".">
...
</form>
...
I'm not sure if you really need to go to create_account() or not, but if you don't this should work for you.
After I submit the form for the first time and then refresh the form it gets resubmitted and and I don't want that.
Here's my form in template :
<form action = "" method = "POST"> {% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Shout!"/>
</form>
How can I fix this ?
Here's my views:
def index(request):
shouts = Shout.objects.all()
if request.method == "POST":
form = GuestBookForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
shout = Shout(author = cd['author'], message = cd['message'])
shout.save()
form = GuestBookForm()
else:
form = GuestBookForm()
return render_to_response('guestbook/index.html', {'shouts' : shouts,
'form' : form },
context_instance = RequestContext(request))
My guess is that this is a problem in your view.
After successful submission and processing of a web form, you need to use a return HttpResponseRedirect, even if you are only redirecting to the same view. Otherwise, certain browsers (I'm pretty sure FireFox does this) will end up submitting the form twice.
Here's an example of how to handle this...
def some_view(request):
if request.method == "POST":
form = some_form(request.POST)
if form.is_valid():
# do processing
# save model, etc.
return HttpResponseRedirect("/some/url/")
return render_to_response("normal/template.html", {"form":form}, context_instance=RequestContext(request))
Given your recently added view above...
def index(request):
shouts = Shout.objects.all()
if request.method == "POST":
form = GuestBookForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
shout = Shout(author = cd['author'], message = cd['message'])
shout.save()
# Redirect to THIS view, assuming it lives in 'some app'
return HttpResponseRedirect(reverse("some_app.views.index"))
else:
form = GuestBookForm()
return render_to_response('guestbook/index.html', {'shouts' : shouts,
'form' : form },
context_instance = RequestContext(request))
That will use reverse to redirect to this same view (if thats what you are trying to do)
Try:
return redirect ('url', parameter_if_needed)
instead of
return render (request, 'name.hmtl', context)
In my case it works perfectly.
Most likely: When you refresh after submitting the form, you are showing the same form page again (without doing anything). You either need to redirect to the record page or a new page after the form has been submitted.
That way, the form becomes empty its data and will not resubmit when you refresh.
I have found a way and I think it's going to work for any website. what you have to do is add a Htmx cdn or you can call the javascript library from htmx.org like bootstrap CDN.
add this
before body tag
<script src="https://unpkg.com/htmx.org#1.6.0"></script>
add this or go to their website htmx.org
then what you have to do is go to your form tag and add this....
hx-post=" then add the path in here, where you want to redirect" something like this..
contact html
<form hx-post="/contact" hx-target="body" method="post">
</form>
you have to add a target depending on your form type. The above example is a contact form I want that contact form to stay on the same page and target its body like this hx-target="body"
views.py
return render(request, "blog/contact.html")
Use HttpResponseRedirect
create a new view(lets say thank_you) for successful message to display after form submission and return a template.
After successful form submission do return HttpResponseRedirect("/thank-you/") to the new thank-you view
from django.http import HttpResponseRedirect
def thank_you(request, template_name='thank-you.html'):
return render_to_response(template_name,locals(),context_instance=RequestContext(request))
and in urls.py
url(r'^thank-you/$','thank_you', name="thank_you")
Multiple form submission happens because when page refreshes that same url hits, which call that same view again and again and hence multiple entries saved in database. To prevent this, we are required to redirect the response to the new url/view, so that next time page refreshes it will hit that new url/view.
This solution worked for me. After form submission we have have to display a message in our template in form of popup or text in any form so though HttpResponseRedirect may prevent form resubmission but it won't deliver the message so here is what I did.
from django.contrib import messages
def index_function(request):
if request.method == "POST":
form = some_form(request.POST)
if form.is_valid():
# do processing
# save model, etc.
messages.success(request, 'Form successfully submitted') # Any message you wish
return HttpResponseRedirect("/url")
Then inside your template, you can show this message. Since this is global parameter you can display it in any HTML template like the following.
{% if messages %}
<div class="alert alert-success alert-dismissible">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}