Refresh Django wizard form after browser's back button - django

I am using SessionWizardView from django-formtools project.
I've noticed that after successfully passing all form checks and executing done() function, which redirects to completely different view, user can still hit browser Back button and re-fill form again.
Isn't there any way to prevent that? I would assume that it would be some kind of session cleaning mechanism. But I cannot find any in documentation.

After some playing around I've found that it can be achieved in two lines:
def done(self, form_list, form_dict, **kwargs):
#regular form processing
self.instance_dict = None
self.storage.reset()
Now, after pressing Back button and submitting form it fails because no data exists and resets to first screen.

Related

Django Form resubmit issue when press back button [duplicate]

strong textI am trying to prevent a page being cached as I dont want the user to be able to resubmit a form which has already been saved to the db.
I tried the following in views.py
class ServiceCreate(LoginRequiredMixin, CreateView):
model = Service
form_class = ServiceCreateForm
#method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
return super(ServiceCreate, self).dispatch(request, *args, **kwargs)
However, this has no effect as the entire page is shown instantly when the user hits the back button. How can I prevent caching please?
Update
I'm new to Django so thought that the decorator would instruct the browser not to cache - I did not appreciate that there was server caching as well.
What you're seeing has nothing to do with server caching- it is all browser side.
Ultimately you can't 100% guarantee that a form won't be submitted multiple times (users will find a way...), so you'll have to handle that gracefully on the server. However you can greatly reduce the likelihood of it:
Return an HttpResponseRedirect (or use the redirect shortcut) to redirect the browser after a successful form submission. This will prevent a browser refresh from resubmitting the form.
Use javascript to disable the form submit button after the form as been submitted. I recently had some weird errors and data inconsistencies that turned out to be caused by someone double clicking a form's submit button. Disabling the button after the first click resolved the issue (along with doing more validation server-side to recognize a duplicate submission).
Make sure that you use POST (rather than GET) to submit the form. Browsers are less likely to resubmit the form casually and I believe that Django's CSRF protection should also help prevent errant submissions.

Django - How to stay on the same page without refreshing page?

I am using Boostrap modal fade window which renders Django form to update my database records. And what I fail to do is not to reload the page if the user has opened the Update window and did not change anything. It will be easier to get my idea if you look at the code below:
def updateTask(request, task_id):
#cur_usr_sale_point = PersonUnique.objects.filter(employees__employeeuser__auth_user = request.user.id).values_list('agreementemployees__agreement_unique__sale_point_id',flat=True)
selected_task = Tasks.objects.get(id=task_id)
task_form = TaskForm(instance=selected_task )
taskTable = Tasks.objects.all()
if request.method == 'POST':
task_form = TaskForm(request.POST,instance=selected_task)
if task_form.has_changed():
if task_form.is_valid():
# inside your model instance add each field with the wanted value for it
task_form.save();
return HttpResponseRedirect('/task_list/')
else: # The user did not change any data but I still tell Django to
#reload my page, thus wasting my time.
return HttpResponseRedirect('/task_list/')
return render_to_response('task_management/task_list.html',{'createTask_form':task_form, 'task_id': task_id, 'taskTable': taskTable},context_instance=RequestContext(request))
The question is, is there any way to tell Django to change the url (like it happens after redirecting) but not to load the same page with same data for the second time?
It's not trivial, but the basic steps you need are:
Write some javascript to usurp the form submit button click
Call your ajax function which sends data to "checking" view
Write a "checking" view that will check if form data has changed
If data have changed, submit the form
If not, just stay on page
This blog post is a nice walkthrough of the entire process (though targeted towards a different end result, you'll need to modify the view).
And here are some SO answers that will help with the steps above:
Basically:
$('#your-form-id').on('submit', function(event){
event.preventDefault();
your_ajax_function();
});
Call ajax function on form submit
Gotta do yourself!
Submit form after checking

Django prevent page caching

strong textI am trying to prevent a page being cached as I dont want the user to be able to resubmit a form which has already been saved to the db.
I tried the following in views.py
class ServiceCreate(LoginRequiredMixin, CreateView):
model = Service
form_class = ServiceCreateForm
#method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
return super(ServiceCreate, self).dispatch(request, *args, **kwargs)
However, this has no effect as the entire page is shown instantly when the user hits the back button. How can I prevent caching please?
Update
I'm new to Django so thought that the decorator would instruct the browser not to cache - I did not appreciate that there was server caching as well.
What you're seeing has nothing to do with server caching- it is all browser side.
Ultimately you can't 100% guarantee that a form won't be submitted multiple times (users will find a way...), so you'll have to handle that gracefully on the server. However you can greatly reduce the likelihood of it:
Return an HttpResponseRedirect (or use the redirect shortcut) to redirect the browser after a successful form submission. This will prevent a browser refresh from resubmitting the form.
Use javascript to disable the form submit button after the form as been submitted. I recently had some weird errors and data inconsistencies that turned out to be caused by someone double clicking a form's submit button. Disabling the button after the first click resolved the issue (along with doing more validation server-side to recognize a duplicate submission).
Make sure that you use POST (rather than GET) to submit the form. Browsers are less likely to resubmit the form casually and I believe that Django's CSRF protection should also help prevent errant submissions.

Django SessionWizardView jumps back to the first step after page is reloaded

I am working with a SessionWizardView which is managing two forms. When I reload the page at the last step for instance I am back at the first step and have to type in all the fields again.
Is this the intended behaviour? If so, is it possible to get back to step I was at before I reloaded the page? Of course all the fields should be filled out accordingly.
class ManufacturingCalculatorWizard(SessionWizardView):
def get_template_names(self):
TEMPLATES = {
"blueprint": "manufacturing/forms/select_blueprint.haml",
"calculator": "manufacturing/forms/calculator.haml"
}
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
rcontext = RequestContext(self.request, { 'data' : calculate_manufacturing_job(form_data) })
return render_to_response('manufacturing/forms/result.haml', rcontext)
Page rendered after done method is not part of wizard, so when you reload it, django will try to redirect to first page as new session of wizard.
If you want to add last step as something like preview and confirmation page, you can add a new step with dummy form and show appropriate data using the template. To get data from previous steps you can make use of get_context_data method of view, to build context with cleaned data of previous forms.

Model.objects.all() won't refresh using djangoappengine

I'm wondering if the queryset manager in django-nonrel is broken, but I may just be missing something about how to use it. Here's my issue:
I've put together a simple blog using Django, but using djangoappengine. The model I use for the blog entries is called an Entry.
I have a view for deleting entries. Once an entry is deleted, it redirects to the home page, which lists all the remaining entries. The trouble is, the first time the redirect happens the entry which I just deleted remains there. If I refresh the page, it disappears from the list. The issue seems to be that even though I call Entry.objects.all() after deleting the entry, it is caching the values from earlier.
I moved the code over to a normal Django project and this bug didn't manifest, so I think it's to do with the queryset manager in django-nonrel.
I've tried doing lots of different things but I can't work out how requery the database. Here's some code for the view - I've simplified it so it doesn't even redirect, it just renders to response the entry_list with a call to Entry.objects.all(). Still the same problem.
def update_or_delete_object(request, *args, **kwargs):
"A wrapper around the generic update_object view which allows a delete button too."
if request.method == 'POST' and 'delete' in request.POST:
#If they've just clicked the delete button
object = get_object_or_404(Entry, pk=kwargs['object_id'])
object.delete()
return render_to_response('entry_list.html', {'object_list':Entry.objects.all()})
return update_object(request, *args, **kwargs)
Any ideas?