Django - refine search results via a searchform with prefilled values - python

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.

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'], {})

Redirecting from one form to another form in Django

I have two form pages:
Start Form - where you input the basic information
Add product form - uses data from start form to populate some fields. And there you can also give more information in the form.
In the urls.py I have this:
urlpatterns = patterns('',
url(r'^$',add_product_start),
url(r'^add_product/$', add_product),
)
This is my add_product_start form view:
def add_product_start(request):
form = add_product_start_form()
if request.method == "POST":
form = add_product_start_form(request.POST)
if form.is_valid:
#return respose to the add_product url with request data
return render(request,'index.html',{'form':form})
And this is my add_product view:
def add_product(request):
images = []
if request.method == "POST":
initial = {field:value for (field,value) in request._post.iteritems() if value}
#a bunch of other code
#point is I want to receive post data from add_product_start view and at the same time redirect to a different url, because I don't want to have the same url of two different forms.
return render(request,'add_product.html' ,{'form':form,'images':images})
I know there is something like HttpResponseRedirect but they just redirect me to the page without any type of data.I want to get the data from the start form, validate it, and if valid pass it to the second view with a different page.
Can someone please help me. Thank you very much!
The best way is using the form wizard https://docs.djangoproject.com/en/1.7/ref/contrib/formtools/form-wizard/
I solved similar issue using redirect(obj).
This video may help
https://www.youtube.com/watch?v=YsHd-l7QdI8

How do I pass a list from one view to another in Django?

I've been scouring StackOverflow, but I haven't found an answer to this that works for me. I am relatively new to Python and Django, so maybe I'm thinking about it wrong.
To make a simple example, imagine two views with different associated URLs. This is not supposed to be perfect code. I'm just trying to figure out how to get a variable-length list of items from view 1 into view 2. I don't see a way to do it via the URL because the list may be variably long. Shouldn't this be extremely easy to do?
def view2(request, list_to_process):
use list_to_process to manufacture formset (e.g. make a formset with one entry for each item in the list)
return render(request, 'Project/template2.html', {'formset': formset})
def view1(request):
if request.method == "POST":
if form.is_valid():
result = form.cleaned_data
list_to_process = []
for item in result:
list_to_process.append(item)
*WHAT CODE DO I USE HERE TO CALL VIEW2 AND SEND IT list_to_process AS AN ARGUMENT OR REQUEST ADDITION?*
else:
formset = formsettype()
helper = AssayHelper() (defined elsewhere)
helper.add_input(Submit("submit", "Submit")
return render(request, 'Project/template1.html', {'formset': formset, 'helper': helper})
Can someone please help? Thanks.
That is exactly what the session is for. In view 1:
request.session['list'] = list_to_process
And in view 2:
list_to_process = request.session['list']
If you are willing to use session then go with the answer given by #Daniel,
But in your case it seems that you are not going on separate url, you just need to render it in the same url but need the output from that view, in that case take help from named paramter of python functions like this -
def view2(request, list_to_process=None, **kwargs):
use list_to_process to manufacture formset (e.g. make a formset with one entry for each item in the list)
return render(request, 'Project/template2.html', {'formset': formset})
def view1(request):
if request.method == "POST":
if form.is_valid():
result = form.cleaned_data
list_to_process = []
for item in result:
list_to_process.append(item)
return view2(request, list_to_process=list_to_process)
else:
.....
The benefit of using named parameter is that, they are optional and thus will not throw error if they are not provided, for example, when that view is called directly instead from inside view1

Django multiple forms 1 view..Form errors issue

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.

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.

Categories

Resources