Django form submit again on refresh - python

Hello I am working on a simple form. The form submits fine but if I refresh the page it resubmits the data. Seems the form is holding the data after submit and I assume since after the submit the request method is post. Question is what is the best way after the submit to clear the form in Django. After the submit the form variables should not be holding the values anymore. Thanks
def testimonials(request, template_name="testimonials.html"):
reviews = Reviews.objects.all()
if request.method == 'POST':
form = forms.ReviewsForm(data = request.POST)
# create a new item
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
if form.is_valid():
nameIn = form.cleaned_data['name']
reviewIn = form.cleaned_data['review']
newReview = Reviews(name = nameIn, review = reviewIn)
newReview.save()
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
else:
# This the the first page load, display a blank form
form = forms.ReviewsForm()
return render_to_response(template_name, locals(), context_instance=RequestContext(request))

Typically, you would issue a redirect after processing a form/POST request (this is common web development practice to avoid the resubmission issue you mentioned). So instead of a render_to_response, you might issue a HttpResponseRedirect like so:
if form.is_valid():
# Process form as desired here
# Simple example; use reverse() to avoid hard-coding URLs
return HttpResponseRedirect('/success/')
Check out the using a form in view for a skeleton of how forms are typically processed.

use reverse instead of render to response
if form.is_valid():
nameIn = form.cleaned_data['name']
reviewIn = form.cleaned_data['review']
newReview = Reviews(name = nameIn, review = reviewIn)
newReview.save()
return HttpResponseRedirect(reverse('app_name:url'))

You could also use the 'redirect' shortcut:
from django.shortcuts import redirect
...
return redirect(newReview)
This is assuming you have get_absolute_url defined in your Review Model.
See the docs for more info.

Related

Django: Handling form data after a redirect

I have a Django app with two views (actually more but I'm simplifying). The first view shows a page with details regarding an object and has a form which can be submitted. The second view is called buy the POST request on submitting the form and then redirects back to the first view:
views.py:
def main_view(request):
context = {}
# other view code here
context['form'] = Form()
return render(request, 'mypage.html', context)
def form_view(request):
form_data = Form(request.POST)
if form_data.is_valid():
# process form here
else:
# add an informative message
messages.add_message(request, messages.INFO, "Error message here")
return redirect('url_of_main_view')
The issue I have here is that I want to pass the form data back to the main view, both to prevent the need to fill in the whole form again, and to allow the validation errors to be displayed.
I would normally do this by simply processing the form within one single view, such as:
def view(request):
context = {}
# other view code here
context['form'] = Form()
if request.method == 'POST':
form_data = Form(request.POST)
if form_data.is_valid():
# process form data
else:
# handle messages
context['form'] = form_data
return render(request, 'mypage.html', context)
However, this (in my case at least) would result in a large view as I have a number of different forms that can be submitted from this page. I also like to redirect after a form post to avoid the data being re-submitted if the user refreshes the page.
My questions:
Is this (the first example) indeed a sensible way of structuring the code for handling forms? Is the second example a more sensible way of doing this, or is there a better idea? Perhaps I should perform form validation within the main view then call a separate method to process the form data?
If I were to use the first example, with a separate view to handle a form post, what is the best way to go about handling instances in which the form fails validation and should be passed back to the main view? Should I be using sessions for this, or is there a more efficient/cleaner way of doing this?
Thanks!
Alex

django redirecting back to the page from where the request was made

I implemented in django return to original page via redirect see view example
#login_required
def category_edit(request, pk,uri):
post = get_object_or_404(Category, pk=pk)
if request.method == "POST":
form = CategoryForm(request.POST, instance=post)
if form.is_valid():
category = form.save(commit=False)
category.author = request.user
category.creation_time = timezone.now()
category.save()
return redirect(uri)
#return redirect('category_details', pk=post.id)
else:
form = CategoryForm(instance=post)
return render(request, 'item/category_edit.html', {'form': form})
So basically after each operation like edit,new I redirect back to from where the call was originally made. (I stoped using it in case of delete since in case of delete the page might not exist any more)
However in one of my questons somebody mentioned that it is better approach to add a path to URL instead of sending URL as parameter to add it in the link
Delete
From samples and documentation I figured out this approach should automatically work in django if I have in my settings in 'context_processors' included 'django.template.context_processors.request'. (However the samples I saw where dated to previous versions of Django)
But this approach didn't work. So my question is does ?next={{request.path}} is still supported in Django 1.8 and if yes what step I am missing.
Any feedback on what approach is better the redirect or the ?next={{request.path}} is welcome as well.

django-form show form data after saving it

I want to show same data to user as posted by him using form after saving it in database.
I am not getting the logic for it.
I am trying to do something like this:
def CreateDeal(request):
if request.method == "POST":
form = DealForm(request.POST)
if form.is_valid():
form.save(commit = True)
data = form.data
return render(request, '/path_to/deal_detail.html',data=data)
Is it ok ?
Is there any better way to do it?
If you do it this way, a redirect of the "detail" page will resubmit the form. This is generally not desired behaviour.
A better way would be to create a detail view for you saved object (if you haven't already) and redirect the user to the detail view of that particular object:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
def CreateDeal(request):
if request.method == "POST":
form = DealForm(request.POST)
if form.is_valid():
obj = form.save(commit=True)
return HttpResponseRedirect(reverse('deal-detail-view', args=(obj.id,)))
# or return HttpResponseRedirect(obj.get_absolute_url())
# if `get_absolute_url` is defined

Django - best practice for getting ID from querystring into edit view

I'm wondering what the acceptable best practice is for pulling an id from a url for use in the edit view. Most example code I see uses slugs, which I don't need to deal with because SEO is not a concern.
Say I have something like:
def article_edit(request):
if request.method == 'POST': # If the form has been submitted...
#a = get_object_or_404(Article, **?XXX?**)
#a = Article.objects.get(pk=**?XXX?**)
form = ArticleForm(request.POST, instance=a) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
return redirect('/articles/') # Redirect after POST
else:
form = ArticleForm() # An unbound form
return render(request, 'article_form.html', {'form': form})
Where I have commented out two possible options for populating a with an Article object based on the ID submitted in the POST. The ?XXX? indicates that I'm not sure how to reference the passed in id.
Any input on those two options, as well as alternative options are appreciated.
Passed in id should go in the url itself, like:
url(r'^articles/(?P<id>\d+)/edit/$', 'views.article_edit', name = 'article_edit'),
Then, in the view you can reference it from the view argument id:
def article_edit(request, id):
if request.method == 'POST': # If the form has been submitted...
article = get_object_or_404(Article, pk=id)
Also, take a look at Writing a simple form chapter of django "polls" tutorial - the same approach is used.
Hope that helps.
try this:
urls.py :
url(r'^articles/(?P<article_id>\d+)/edit/$', 'views.article_edit', name = 'article'),
views.py:
def article_edit(request, id):
if request.method == 'POST':
article = get_object_or_404(Article,id=article_id)

Django: construct form without validating fields?

I have a form MyForm which I update using ajax as the user fills it out. I have a view method which updates the form by constructing a MyForm from request.POST and feeding it back.
def update_form(request):
if request.method == 'POST':
dict = {}
dict['form'] = MyForm(request.POST).as_p()
return HttpResponse(json.dumps(dict), mimetype='application/javascript')
return HttpResponseBadRequest()
However, this invokes the cleaning/validation routines, and I don't want to show error messages to the user until they've actually actively clicked "submit".
So the question is: how can I construct a django.forms.Form from existing data without invoking validation?
Validation never invokes until you call form.is_valid().
But as i am guessing, you want your form filled with data user types in, until user clicks submit.
def update_form(request):
if request.method == 'POST':
if not request.POST.get('submit'):
dict = {}
dict['form'] = MyForm(initial = dict(request.POST.items())).as_p()
return HttpResponse(json.dumps(dict), mimetype='application/javascript')
else:
form = MyForm(request.POST)
if form.is_valid():
# Your Final Stuff
pass
return HttpResponseBadRequest()
Happy Coding.

Categories

Resources