I would like to crate a form whith two submit buttons: Save, let's say, and Back to edit. (The form is meant for a preview / confirm view of stuff that is currently being edited).
For obvious reasons the Save button has a formaction attribute with value post and the other button get. For the post action to work, I include the usual csrfmiddlewaretoken in the form.
So far all works well, the only problem is that the csrfmiddlewaretoken value is now included in the GET requests (which seems to be discouraged for security reasons).
Currently I add some custom javascript that finds all submit buttons with get action and adds a click handler that removes the csrfmiddlewaretoken from the field before submit. This seems a rather wierd and roundabaout way to do things.
Question: Is there a better / more standard / more stable way to handle this situation?
Edit: Why do I want to use get requests for some form actions?
Well, I would like to stick to the rule to use POST requests (only) for requests that change data (and in that case respond with a redirect).
As an example, think of a form where the user can edit ("page A") some fields, and then can press "preview" (a GET action), which leads "page B" where the same form is presented, but readonly, with a preview image generated by the system. If the user is happy, they can press "save" (a POST action) which will actually save the data, or they can press "back" (a GET action, similar to the Browser's back button), to continue editing the data. I would not be happy to implement this "Back" operation as POST, as this messes up the interaction with the actual Browser back button etc.
In this simple example, one could of course ask the user to use the browser back button instead of a form button, or (probably?) use javascript to simulate a browser back. But with slightly more complicated flow control a simple "back" is not an option.
The problem is that you send GET request from the form that contains your CSRF token. I would rather recommend PUT request than GET request. The CSRF token value is not exposed on the URL because the PUT request allows the body value to be passed.
About HTTP PUT method
Related
I am building a review form that will post to a single model in my database. This form will have multiple sections, each with its own set of questions. I want the user to be able to complete a section and hit a submit button that will save the progress and redirect them to the next section. In essence I want to create an in progress status for the review with the idea that as all sections are finished the user can hit a complete button that will run my validation on the entire form. However, I do not want to allow posting information to the database that has not been cleaned.
I've been thinking through this trying to work out what I need to do and believe the best bet would be to have a complete button on the last page that changes blank to False for the fields of the form. I believe this would allow me to fill out each form and post it to the database as all fields would start as optional but then for that specific model instance the click of the button at the end would institute a change making all fields required, thereby running validators to ensure the form is complete. I believe this will also allow for saving progress and returning to it later if interrupted during completion of the form.
Can anyone provide any insight on if this is even possible? If so does anyone have examples that could guide me?
You can store the unvalidated data to the user's session. The final stage pulls all previous step data out of the session for validation. IIRC the Django form wizard does just this so you don't have to write it.
I might instead do this client-side, using one big (probably Crispy) form, and some client-side pseudo-submit buttons that just invoke Javascript to hide one section of the big form and reveal the next. The final one is a real submit, and redisplay of the whole thing if there are errors.
First of all, I only started using Django a week ago... so pretty new :).
I have a one page website. At the bottom there is a contact form. I am using different components for the website, so for the contact form I have 'contact.html' which is loaded into index.html via {& include ... &}. When someone sends a message via contact form, after click send, the user returns to the same page but with a thank you message instead of the contact form (see screenshot).
The issue is that I need to 'kill' the process going on underneath because if I reload the page a message pops and if I resubmit, email gets resend again (see screenshot).
I have had a look at httpresponse but I am unsure how to replicate the same process. Anyone could help?
This is a screenshot of contact.html and views.py
Two things.
I would first consider using a front end framework such as react. (will make your life easier)
Secondly, your code seems fine, you are sending the email twice because you are submitting the form twice.
perhaps redirect the user to a different page upon submission. there is no need to reload the page yourself.
I would have a form, then a confirmation page.
Better yet, write an api, and upon response from the server simply create a popup saying success/fail etc...
I'm uploading an image file in a basic Django web app. There's an upload button in the html template wrapped around by a form tag. Once the upload button is pressed, the underlying view takes over and processes image upload.
In the Chrome browser of my colleague's Macbook, pressing upload multiple times really quickly manages to call the underlying function multiples times too. I end up getting a plethora of copies of the image being uploaded.
However, this isn't replicatable in my own environment's Firefox (Ubuntu OS). Seems this issue is browser sensitive?
In any case, how do I cut off this code behavior? If the user goes into a click frenzy, I don't want multiple images to go up. Can someone guide me how to handle this in Django? I would prefer a non-JS, server solution too.
Note: Let me know if you need to see my related code.
Many people faces this issue. If the submit button called 3 times wihtout waiting to refresh the browser, it will gonna add 3 times.To prevent that you can use jQuery.
For example on form submit you can show the loader or disable the submit button,
$('#login_form').submit(function() {
$('#gif').css('visibility', 'visible');
or
$('#button').prop('disabled', true);
});
Edit for server side implementation:
I do not suggest this for user interface point of view but if you can also valid submits using sessions or cookies.Generate random token in your view and set this in your form as hidden input.
for e.g.,
def checkform(request):
form = ExampleForm(request.POST or None)
randomtoken = #generate random token here and set in session or cookie
if form.is_valid():
# check_token here
session_value == request.POST.get('your_hidden_token')
# if matched than change the random token and save your data else do your restriction processing
render ( request,'template.html',context={ 'form':form,'randomstring':randomstring } )
I have a form whose submit should only be handled once.
Any extra clicks on the submit button should do nothing, where nothing means also not interrupting the flow of the first submit's POST request, which redirects to a GET when it finishes.
What (if anything) can I return from Django's View's post method to achieve this behavior? Returning an empty HttpResponse as suggested in some other related questions on SO seems to interrupt the browser and display an empty page, thus interrupting the GET redirect which I'd like the browser to wait for.
Looking for a server-side solution here, not just javascript disable of the submit button.
Also, I can't just redirect the user to the GET page immediately on the second submit, since the page shows a success status and I'm only interested in showing that once the handling of the first POST is complete, which may take a few seconds.
I am working on a site that would allow users to post some data. To successfully add a new post, the users need to go through three states: Form -> Preview -> Posted page. I want to restrict the users from going back to the Preview page with the browser "back button" once they have already reached the Posted page (instead, they should be redirected to the empty Form page). How can I implement this behaviour in Django?
I am not sure how you get this desired behavior from Django as you have limited control over the user's browser. However, in Javascript you can use:
window.location.replace(url);
which will remove history, thus preventing the back button from working.
See this stack overflow question about window location:
What's the difference between window.location= and window.location.replace()?
An idea: from your preview page, use AJAX to submit and if all is successful, window.location.replace to your posted page.
I can't speak for how to deal with this using browser technologies but with django you could just set a flag in the session.
# posted_page view
request.session['posted_page_visited'] = True
# preview_page view
if request.session.get('posted_page_visited'):
del request.session['posted_page_visited']
return http.HttpResponseRedirect("form_page")
Using js (window.location.replace(url)) doesn't fulfill this requirement because "replace url" will just replace the page with another one,Ex: if form flow goes from page1 to page2 then page3 then page4 and (window.location.replace(url)) is used in page2 (window.location.replace(page4);) then page3 will never be visited!! moreover user will still be able to go back in the same forward path meaning from page4 to page2...etc
the good thing, you can solve it by using Django session as shown below assuming users will be able to go back and forth as long as form not yet saved, and once its saved they can't go back anymore:
in page1/view function where first part of form is issued create session varaible:
in view1.py
def view1(request)
.
.
.
request.session['forward'] = True
return redirect(....)
in view2.py:
def view2(request):
if not request.session['forward']:
return redirect(..Select whatever page you want to redirect users to it..)
the same in rest of pages views..
in the last page/view where after saving the form, reset the variable:
request.session['forward'] = False
return redirect(..Select whatever page you want to redirect users to it..)
hopes its clear enough
django's form wizard should do what you want:
How it works
Here’s the basic workflow for how a user would use a wizard:
The user visits the first page of the wizard, fills in the form and submits it.
The server validates the data. If it’s invalid, the form is displayed again, with error messages. If it’s valid, the server saves
the current state of the wizard in the backend and redirects to the
next step.
Step 1 and 2 repeat, for every subsequent form in the wizard.
Once the user has submitted all the forms and all the data has been validated, the wizard processes the data – saving it to the
database, sending an email, or whatever the application needs to do.