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.
Related
I am trying to get or create an object when another one is created with a form :
def index(request, log_id, token):
log = get_object_or_404(LogBook, pk=log_id)
logmessages = LogMessage.objects.filter(logbook=log_id)
form = CreateLogMessage(request.POST)
if request.method == "POST":
if form.is_valid():
instance = form.save(commit=False)
instance.reported_by = request.user
instance.logbook = log
instance.save()
logdone = LogDone.objects.get_or_create(logmessage=logmessages, done_status=False)
I am trying to figure out a way to get the id of the logmessage created to pass it to my logdone instance.
I don't find a way to do it so far, any help will be appreciate it.
The object that is created is the instance, you thus can implement this as:
from django.shortcuts import redirect
def index(request, log_id, token):
log = get_object_or_404(LogBook, pk=log_id)
if request.method == 'POST':
form = CreateLogMessage(request.POST)
if form.is_valid():
form.instance.reported_by = request.user
form.instance.logbook = log
instance = form.save()
logdone = LogDone.objects.get_or_create(
logmessage=instance,
done_status=False
)
return redirect('name-of-some-view')
else:
form = CreateLogMessage(request.POST)
…
Since your form creates a new object every time, this however always create an object.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
I am working on a web application which works with entities that all have their unique IDs.
I have a submit form for users to create these entities and this form is in several steps (i.e. view 1 redirects to view 2, etc... until the end of the submission process).
The first view will create the ID of the entity after form submission and I then need to use the ID of the instance created in the other views.
I do not want to pass this ID as a URL parameter to the other views as these will be POST and that means that users could easily manipulate these and create records in models for several IDs. I have managed to pass this ID to several views using the session parameters (request.session) but this is not ideal as this is permanent for the session. Current code below:
def view1(request):
if request.method == 'POST':
form = xxx_creation_form(request.POST)
if form.is_valid():
cleaned_form_data = form.cleaned_data
xxx_entry = Model.objects.create(
... object creation ...
)
request.session['xxx_id'] = xxx_entry.id
return HttpResponseRedirect(reverse('form_2'))
else:
form = xxx_creation_form()
return render(request, 'xxx_form.html', {'form': form})
def view2(request):
xxx_id = request.session['property_id']
if xxx_id == 'SET_BACK_BLANK':
return render(request, 'no_xxx_id.html')
if request.method == 'POST':
form = xxx_form2(request.POST)
if form.is_valid():
cleaned_form_data = form.cleaned_data
xxx_entry = Model.objects.create(
id = xxx_id, #use the id created in step 1
... rest of object creation ...
)
request.session['xxx_id'] = 'SET_BACK_BLANK' #to avoid the misuse during other user interactions.
return HttpResponseRedirect(reverse('thanks'))
else:
form = xxx_form2()
return render(request, 'xxx_form2.html', {'form': form})
Ideally, I would like to pass this ID parameter in the headers of the response as this will avoid having the ID as a session parameter. So I have amended the code to the below:
def view1(request):
if request.method == 'POST':
form = xxx_creation_form(request.POST)
if form.is_valid():
cleaned_form_data = form.cleaned_data
xxx_entry = Model.objects.create(
... object creation ...
)
response = HttpResponseRedirect(reverse('form_2'))
response['xxx_id'] = xxx_entry.id
return response
else:
form = xxx_creation_form()
return render(request, 'xxx_form.html', {'form': form})
def view2(request):
xxx_id = HttpResponseRedirect(request).__getitem__('xxx_id')
if request.method == 'POST':
form = xxx_form2(request.POST)
if form.is_valid():
cleaned_form_data = form.cleaned_data
xxx_entry = Model.objects.create(
id = xxx_id, #use the id created in step 1
... rest of object creation ...
)
return HttpResponseRedirect(reverse('thanks'))
else:
form = xxx_form2()
return render(request, 'xxx_form2.html', {'form': form})
However the above does not work and the error message seems to indicate that there is no 'xxx_id' in the response header.
It would be great if anyone could let me know how to access a response's header in a view as it seems that we cannot amend the request's headers.
Thanks.
What you're asking doesn't really make sense. The response is what is sent from Django to the browser, it is not what the browser sends to Django. That's a completely separate request; in the case of a redirect, your response is simply an instruction to the browser to make that request to a new URL.
The correct thing to do is to use the session, as you are doing. If you are worried about the value being persisted, then pop it out of the session when you use it:
xxx_id = request.session.pop('property_id')
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
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)
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.