Django form input and action linking - python

How do you pass form inputs to a form action in Django? I tried this but it's not working
<form action="/search?search_term=q" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>

I'm assuming you're asking how to link an HTML form to a view function for processing. Note that in Django, we don't call them actions.
Here's the basic form and placeholder for the search results that you'd put in a Django template:
<form action="/search" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
{% if search_results %}
Display search results here.
{% endif %}
If you type apple into the text field and then click the search button on this form it will make a GET request to /search?q=apple.
You will need to route the request via a URLconf to a view function to do the processing.
The entry in the URLconf may look like the following:
from django.conf.urls import url
from app import views
urlpatterns = [
# ...
url(r'^search/$', views.search),
# ...
]
views.search is the view function that does the processing. Here's a possible implementation:
from django.shortcuts import render
def search(request):
q = request.GET.get('q')
if q is None:
return render(request, 'app/search.html')
search_results = perform_search(q)
context = { 'search_results': search_results }
return render(request, 'app/search.html', context)
Where perform_search is a function you'd need to write to do the actual searching.

When you specify a method GET in form, then You don't need to append parameters explicitly in the URL. When the user submits the form your parameter will automatically append in the URL as key-value pairs.
Example
<form action="search" method="GET">
<input type="text" name="search_item1">
<input type="text" name="search_item2">
<input type="submit" value="Search">
</form>
When a user hit submit button then your parameter(serach_item1 and serach_item2) will append implicitly in action URL. where keys are input fields name attribute
Now your URL looks like
www.example.com/search?search_item1=<serach1>&search_item2=<serach2>

To pass GET arguments to the page you don't need to specify it in action attribute.
Just do follow:
<form method="GET" action="search/">
<input type="text" name="search_term" value="{{ request.GET.search_term }}">
<input type="submit" value="Search">
</form>
this will redirect you to the page http://yourdomain.com/search?search_term=search_text.
Please note I replaced input name attribute to rename GET argument to search_term. Also I added value attribute to display current search text to the input field.

shuboy2014 and neverwalkaloner are correct. But a fact they didn't tell you is that you'll pass empty values if you declare no values in that fields. For example:
<form method="GET" action="search/">
<input type="text" name="search_term">
<input type="submit" value="Search">
</form>
That would create an URL like http://yourdomain.com/search?search_term=, which could lead to unexpected errors in the View later. You either should do request.GET.get("search_term") to avoid exceptions or modify the submit function of your form to dinamically remove the names of those empty fields.

Related

Delete an object in Django

I am trying to delete an object. This is the HTML, todo should be deleted when you Click on button (I am trying to call delete_todo) :-
<ul>
{% for all %}
</ul>
This is the views.py,
You need to change few things in your code.
First of all change urlpattern delete_todo you need to add argument, which allows to determine in view what object you want to delete:
url(r'^(?P<todo_id>[0-9]+)/$', views.delete_todo, name='delete_todo'),
Then you need change delete_todo itself:
def delete_todo(request, todo_id):
instance = get_object_or_404(Todo, pk=todo_id)
instance.delete()
return redirect('index')
Here you can use get_object_or_404 fuction to get object with id.
And finally you need to pass url's argument to view from template:
<form action="{% url 'lists:delete_todo' todo_id=todo.id %}" method=post>
<input id="submit" type="button" value="Click" />
</form>
Just to add clarification on the use of the form and csrf: it's necessary in order to ensure that different users of your app can't delete content that isn't theirs.
In your template, you'll need to include the csrf tag as such:
<form method="post" action={% url 'delete_todo' todo_id=todo.id %}>
{% csrf_token %}
<input type="button" id="submit" value="Delete" />
</form>

Flask - generate url with parameters in html

I am trying to find how I can pass a URL parameter (not request) into the url_for function, but I cant find it. In the following example, I need to pass the q_id through the form, as I do with incrRight. So, how can I have variables in url_for in this scenario ?
<form action="{{url_for('answer',q_id='5495eb77433f064294361ceb')}}" method="post">
<input type="text" name="incrRight" value="0">
<input type="submit"/>
</form>
This is what I have on my controller:
#app.route('/api/v1.0/question/<string:q_id>/answer', methods = ['POST'])
def answer(q_id):
incrRight = request.form.get('incrRight')
. . .
I need my html form to be able to communicate with the above function, by passing a q_id and the incrRight parameter.
You can add additional form parameters by adding more <input> tags. If the user of the form is not supposed to changed the items, use a <input type="hidden"> element:
<form action="{{ url_for('answer') }}" method="post">
<input type="text" name="incrRight" value="0" />
<input type="hidden" name="q_id" value="5495eb77433f064294361ceb" />
<input type="submit"/>
</form>
This does require that the answer() view can be invoked without the q_id parameter, of course:
#app.route('/api/v1.0/question/answer', methods=['POST'])
#app.route('/api/v1.0/question/<string:q_id>/answer', methods = ['POST'])
def answer(q_id=None):
if q_id is None:
q_id = request.form['q_id']
incrRight = request.form.get('incrRight')
Here a missing q_id parameter in the URL signals to the view that the browser included the question id in the POST body instead.
Another option is for you to write JavaScript code that'll adjust the form action parameter based on the q_id field in the form, but this then requires that your visitors have JavaScript enabled.

Django: Template {% url %} tag, how to pass parameter from form

There is template:
<form action="{% url 'nfoapp.views.kinoscrap' <I WANT MOVIE_ID THERE> selectshort.id %}" method="post">
<input type="text" class="form-control" name="MOVIE_ID">
<button type="submit" class="btn btn-danger">Kinopoisk Search by ID</button>
</form>
There is my urls.py:
(r'^kinoscrap/(?P<kinoid>\d+)/(?P<shortid>\d+)/$', kinoscrap),
I want pass to kinoscrap two parameters - text field from form (MOVIE_ID) and 'selectshort.id' variable. The problem is that i can't put simple MOVIE_ID in first line of template, I got error. But when I try put instead MOVIE_ID other variable, for example selectshort.id, program work without error.
How I can trasmit text field value to view?
p.s I use bootstrap, if it has some importance.
You could have the form action empty, so to the same view, and then in the view redirect using the POST data from the form.
<form action="" method="post">
<input type="text" class="form-control" name="MOVIE_ID">
<button type="submit" class="btn btn-danger">Kinopoisk Search by ID</button>
</form>
And then in the view
def searchView(request):
if request.method == 'POST':
# get variables from form and redirect
else:
# do your normal rendering
(r'^kinoscrap/(?P<kinoid>\d+)/(?P<shortid>\d+)/$', kinoscrap),
Your urls.py accepts to integer values in the url (something like kinnoscrap/12/21), if you pass anything beside integers it'll throw an error. If you want to pass a text field you'll have to change the regular expression.
Try out your regexes at regex101 here to see if they'll work.

POST data has wrong value for Django template variable?

I have the following code in my template:
<form action="" method="post">{% csrf_token %}
{%for category, category_votes in votes%}
<p>{{category}}: {{category_votes}} <!-- displays as expected -->
<input type="hidden" name="votedCat" value="{{category}}" id={{forloop.counter}}>
<input type="submit" name="upvote" value="Vote for...">
<input type="submit" name="downvote" value="Vote against...">
</p>
{%endfor%}
</form>
The variable {{category}} displays as expected when rendered, but looking in the POST data, "votedCat" is always the last category value in votes.
For example, if votes=[('a',1),('b',2),('c',3)], then request.POST['votedCat'] returns 'c' regardless of which input button is used to submit the form. What did I do wrong?
Because you only have one single form, with multiple inputs for votedCat. Clicking any of the buttons submits the whole form, with all the values for votedCat. If you were to access request.POST.getlist('votedCat') you would see that you actually have all the values.
There are two ways of fixing this. The first is to have separate form elements for each iteration through the loop - to do that, just move the <form> and </form> elements inside the loop.
The second is to have the votedCat input actually be the submit button:
<input type="submit" name="votedCat" value="Vote for {{category}}" id={{forloop.counter}}>
The disadvantage here is that now you have the words 'Vote for' in your variable, which you'll need to parse out in the view code.
Better than both of these would be to have a simple radio button set or select box with a single submit button, but I understand that design requirements sometimes get in the way.
Finally, you should really be using Django's forms framework, rather than using manual HTML and dealing with the POST directly.
I'm not sure if this is the best solution, but you can create a new form inside the loop:
{%for category, category_votes in votes%}
<p>{{category}}: {{category_votes}} <!-- displays as expected -->
<form action="" method="post">{% csrf_token %}
<input type="hidden" name="votedCat" value="{{category}}" id={{forloop.counter}}>
<input type="submit" name="upvote" value="Vote for...">
<input type="submit" name="downvote" value="Vote against...">
</form>
</p>
{%endfor%}
You could consider using the django.forms.Form class to build and process your forms.

How to process two forms in one view?

I have two completely different forms in one template. How to process them in one view? How can I distinguish which of the forms was submitted? How can I use prefix to acomplish that? Or maybe it's better to write separate views?
regards
chriss
Personally, I'd use one view to handle each form's POST.
On the other hand, you could use a hidden input element that indicate which form was used
<form action="/blog/" method="POST">
{{ blog_form.as_p }}
<input type="hidden" name="form-type" value"blog-form" /> <!-- set type -->
<input type="submit" value="Submit" />
</form>
...
<form action="/blog/" method="POST">
{{ micro_form.as_p }}
<input type="hidden" name="form-type" value"micro-form" /> <!-- set type -->
<input type="submit" value="Submit" />
</form>
With a view like:
def blog(request):
if request.method == 'POST':
if request.POST['form-type'] == u"blog-form": # test the form type
form = BlogForm(request.POST)
...
else:
form = MicroForm(request.POST)
...
return render_to_response('blog.html', {
'blog_form': BlogForm(),
'micro_form': MicroForm(),
})
... but once again, I think one view per form (even if the view only accepts POSTs) is simpler than trying to do the above.
like ayaz said, you should give unique name to form submit button
<form action="." method="post">
......
<input type="submit" name="form1">
</form>
<form action="." method="post">
......
<input type="submit" name="form2">
</form>
#view
if "form1" in request.POST:
...
if "form2" in request.POST:
...
If the two forms are completely different, it will certainly not hurt to have them be handled by two different views. Otherwise, you may use the 'hidden input element' trick zacherates has touched upon. Or, you could always give each submit element a unique name, and differentiate in the view which form was submitted based on that.

Categories