Django multiple forms 1 view..Form errors issue - python

im having some trouble with displaying form errors within one view. I'm currently a student and have been taking python classes for 2 semesters. I decided to learn some Django on my own.
The issue that i have come across is that im trying to have a multistep process so a user can post a book. But, i want to do it within the same url. so when the user finishes the first form and clicks submit it will go on to the next form but the url wont change. I have figured this out. my issues is that when i get to the second form there are form errors already displaying that appear along with the form. I spend like 3 hours yesterday trying to figure out and no luck.
so if anyone can give a helping hand that would be great! thanks!
def book_post(request):
if request.method == 'POST':
formone = bookFormOne(request.POST)
formtwo = bookFormTwo(request.POST, request.FILES)
if formtwo.is_valid():
#.....do form2 valid stuff
return HttpResponseRedirect('/success')
if formone.is_valid() :
#....do form1 valid stuff
#formtwo = bookFormTwo()..if i add this the errors wont display but then errors from the first form spill over and it wont allow the second form to be valid...###
args = {'form2':formtwo,'isbn':isbn,'subject':subject}
args.update(csrf(request))
return render_to_response('book_post_form2.html', args,context_instance=RequestContext(request))
else:
args = {}
args['form'] = formone
args['form2'] = formtwo
args.update(csrf(request))
else:
form = bookFormOne()
args = {'form':form}
args.update(csrf(request))
return render_to_response('book_post.html', args,context_instance=RequestContext(request))

You don't have any case in which you're displaying an empty formtwo. Passing request.POST to the form and calling is_valid() is going to cause validation to run, which presumably isn't what you intend when the user POSTS formone. As #karthikr suggests, you need to figure out a way to tell what step you're so you can validate and display the appropriate form.
The easiest way might be to add something like args['step'] = 1 when rendering book_post.html and args['step'] = 2 when rendering book_post_form2.html. Then pass that variable back to the server again on POST using a hidden form field, and check it to decide which form you need to validate.

Related

How can I use form data in Django directly as context in another view

I'm having big trouble understanding the whole forms business in django. As I understand it the cleaned form data is a dictionary. So all my defined form fields should be in the dictionary like so: {'definedform': userinput, ...}. Is this correct?
I want to create a form in which a user can input data. This data should then be send to a different view, in which the inputted data is rendered with a latex template (and subsequently rendered into a pdf). This works more or less fine if I define the context in the /create_pdf/ view and grab the user input manually. But I suppose there is a nicer way. What I think should work:
def index(request):
if request.method == "POST":
persoform = PersonalForm(request.POST, prefix='personal')
if persoform.is_valid():
content = persoform.cleaned_data()
content = Context(content)
return HttpResponseRedirect('/create_pdf/')
else:
persoform = PersonalForm()
return render(request, 'app/template.html', {'persoform': persoform})
And in my /create_pdf/ view:
def create_pdf(request):
template = get_template('app/latextemplate.tex')
rendered_tpl = template.render(content)
[...]
So, how can I make sure, to pass the data from my index view to my create_pdf view?
EDIT:
Forgot to mention: The error is "'content' not defined". So I understand that the /create_pdf/ view doesn't get content dictionary, but I have no idea how I would make sure that it does.
Put the data in to the session on submit, and pop it out in the second view.
if form.is_valid():
request.session['perso'] = form.cleaned_data
return HttpResponseRedirect('/create_pdf/')
...
def create_pdf(request):
data = request.session.pop('perso'], {})

How to check if Django form contains any data?

I have Django function view with two forms inside. What is the best solution to detect which form has data typed by user? I know how form.is_valid() works, but still I want to check firstly which form was filled with data.
My code:
def edit_profile_view(request):
if request.method == "POST":
edit_form = EditProfileForm(request.POST)
pass_form = ChangePasswordForm(request.POST)
# here I want to detect which form has data inside,
# and then save this form
else:
edit_form = EditProfileForm()
pass_form = ChangePasswordForm()
template = get_template("profiles/profile_edit.html")
variables = RequestContext(request, {'edit_form': edit_form, 'pass_form': pass_form})
output = template.render(variables)
return HttpResponse(output)
Just have two different actions/views for the forms then the form that has data is the one that the user clicked submit on.
You could, like you say, just check what the form errors actually are or make a method on your forms for is_filled_in but this all seems overkill to me.

django - how to implement a 2-step publish mechanism

I'm new to both web development and django so maybe that's a noob question.
I want to do the following:
Ask user to fill some form and submit it.
Then, parse and format the content and display it back to the user to let him verify it.
User can accept the result or go back to the previous view, update data and resend.
This is as far as I can think:
views.py
def add_content(request):
if request.method == 'POST':
form = AddContentForm(request.POST)
if form.is_valid():
content = form.save(commit=False)
return verify_content(request, content)
else:
form = AddContentForm()
return render(request, 'myapp/add_content.html', {'form' : form})
def verify_content(request, content):
return render(request, 'myapp/verify_content.html', {'content' : content})
The verify_content template will obviously contain two buttons ('back', 'ok'), but I don't know how to pass the content object to a view for saving it in the db, or send it back to the previous view from there. Should I use js? Can i do it with just server side code?
Maybe my whole logic is wrong. Should I save the object in the db before verification and then delete it if needed (sounds ugly)? What is a good way to implement this?
Thanks in advance for your time.
You could use the users session for this:
request.session['content'] = content
and in the view where the user should verify his input do:
content = request.session['content']
and voilá you got the content between 2 views.
Django also secures that users can't tinker with its data by either saving it server side, or in a signed cookie.
I would save the form with commit=True in the add_content view, and would add a verified field or something to the model. Then you can append the pk as GET parameter to the link which will get you back to add_content view from verify. You can extract the parameter from request.GET dict.

POST in django. How does a user update?

I'm brand new to django and fairly new to programming in general. I've done the django tutorial and searched the web for an answer to this question, but to no avail, so now I'm here. I am confused how post works with django. All of the tutorials I've looked at how have a return function in views that displays the webpage. I get that. But then how does a user update data if the page is being rendered from that return statement? After the return there can't be any more updates because the function stops, right? What am I missing here? Any help would be greatly appreciated, I'm getting fairly desperate here.
One pattern for Django views (by no means the only pattern) is to check the request method (GET or POST) at the beginning of the view. If it is POST, then handle the incoming data (before the view returns), and then return either a rendered template, or a redirect.
def view_function(request):
if request.method == 'POST':
if data_is_valid(request.POST):
save_data(request.POST)
return HttpResponseRedirect('/somewhere/good')
else:
return render('template', {'errors': what_went_wrong}
else:
return render('template')
The user updates data in the logic of the view function. That is to say, if the user wishes to update something, you place the update logic in the view function before the return. For example, you would do this:
def update(request):
item = <some model>.objects.get(<something>)
<more code>
return <something>
Usually an edit view function contains two parts -- one for updating data, and the other for displaying the update form. For example,
def user_edit(request):
if request.method == 'POST': # is this a save action?
# save the user data
user_id = request.POST.get('user_id')
username = request.POST.get('username')
description = request.POST.get('description')
user = User.objects.get(id=user_id)
user.username = username
user.description = description
user.save()
return HttpResponseRedirect('/user/') # redirect to index
else:
# show the edit form
user_id = request.GET.get('user_id')
user = User.object.get(id=user_id)
return render_to_response('/user/edit.html', { 'user': user })
There are many different choices for the if request.method == 'POST' line. You can also use if request.POST.get('user_id') to check if specified field is set, to determine if this is a save action.

Django - refine search results via a searchform with prefilled values

On my homepage I have a simple search form. The user can enter some filters and in a next step the search results are diplayed on a new page => this all works:
Below a simplified version of the view.py:
def search(request):
form = SearchForm()
if request.method == 'POST':
form = SearchForm(request.POST)
results = search(form)
return render_to_response('search_results.html',{'results': results},context_instance = RequestContext(request))
else:
form = SearchForm()
return render_to_response('search.html',{'form': form},context_instance = RequestContext(request))
Now the problem:
In a next step I want to add the same searchform in the search_result.html page. The purpose would be that the user can refine the search results using that search form. In an ideal world the search form on search_results.html has already the filters entered in search.html prefilled.
I'm struggling a bit on how to approach this. Should I pass the orginal entered filters as a list to the search_result.html page? How can I do this? And how can I put these values as a default in the form? Maybe I'm overthinking this somehow, but at this moment I don't see a good solution.
Any feedback, directions are very much appreciated!
Thanks!
Can't you just make your context dict {'results': results, 'form': form}? This would make the form available again with the previously posted data already bound to the form.

Categories

Resources