html form - get rid of question mark and equation - python

Here's my code:
{% if request.path == '/employees' %}
<form action="{{ url_for('employees_name', employee_id=x) }}" />
EmployeeId: <input type="text" name=x><br>
<input type="submit" value="Submit">
</form>
{% endif %}
E.g. when I input "1" as an output I get:
http://127.0.0.1:5002/employees/?x=1
but I need this:
http://127.0.0.1:5002/employees/1
Here's my Python code:
app = Flask(__name__)
api = Api(app)
class Employees_Name(Resource):
def get(self, employee_id):
conn = db_connect.connect()
query = conn.execute("select * from employees where EmployeeId =%d " %int(employee_id))
result = {'data': [dict(zip(tuple (query.keys()) ,i)) for i in query.cursor]}
return Response(render_template('test.html', result=result, mimetype='text/html'))
api.add_resource(Employees, '/employees')
Is there a way to do it? Thanks

When using 'GET' to handle form, the form data will be formatted as a query string appended after URL. The normal way is to use a POST endpoint to handle form and validate form data, then redirect to a GET endpoint like yours.
So, the code may like this:
from flask import request, url_for, redirect
...
class Employees(Resource):
def post(self):
employee_id = request.form.get('employee_id')
# validate...
return redirect(url_for('employee', employee_id=employhee_id))
class Employee(Resource):
def get(self, employee_id):
conn = db_connect.connect()
...
api.add_resource(Employees, '/employees')
api.add_resource(Employee, '/employees/<int:employee_id>') # this rule is waht you want
In the template:
<form action="{{ url_for('employees') }}">
EmployeeId: <input type="text" name="employee_id"><br>
<input type="submit" value="Submit">
</form>

Related

Redirection in flask adds a question mark, why? [duplicate]

Here's my code:
{% if request.path == '/employees' %}
<form action="{{ url_for('employees_name', employee_id=x) }}" />
EmployeeId: <input type="text" name=x><br>
<input type="submit" value="Submit">
</form>
{% endif %}
E.g. when I input "1" as an output I get:
http://127.0.0.1:5002/employees/?x=1
but I need this:
http://127.0.0.1:5002/employees/1
Here's my Python code:
app = Flask(__name__)
api = Api(app)
class Employees_Name(Resource):
def get(self, employee_id):
conn = db_connect.connect()
query = conn.execute("select * from employees where EmployeeId =%d " %int(employee_id))
result = {'data': [dict(zip(tuple (query.keys()) ,i)) for i in query.cursor]}
return Response(render_template('test.html', result=result, mimetype='text/html'))
api.add_resource(Employees, '/employees')
Is there a way to do it? Thanks
When using 'GET' to handle form, the form data will be formatted as a query string appended after URL. The normal way is to use a POST endpoint to handle form and validate form data, then redirect to a GET endpoint like yours.
So, the code may like this:
from flask import request, url_for, redirect
...
class Employees(Resource):
def post(self):
employee_id = request.form.get('employee_id')
# validate...
return redirect(url_for('employee', employee_id=employhee_id))
class Employee(Resource):
def get(self, employee_id):
conn = db_connect.connect()
...
api.add_resource(Employees, '/employees')
api.add_resource(Employee, '/employees/<int:employee_id>') # this rule is waht you want
In the template:
<form action="{{ url_for('employees') }}">
EmployeeId: <input type="text" name="employee_id"><br>
<input type="submit" value="Submit">
</form>

form action in flask not redirecting to the route

Simply I am just trying to redirect to an url by using the below code in my login.html template:
<form>
<form action="/sessions">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
and
def login():
print("inside login")
return render_template('login.html')
#app.route("/sessions", methods=["GET","POST"])
def sessions():
userid = request.form.get("userid")
password = request.form.get("password")
return request.form.get("userid"), request.form.get("password")
but is stuck on the login() url. Also I tried
<form action="{{ url_for('sessions') }}">
but is not working as well. Not sure what I am missing? Please any hints/ideas would be highly appreciated.
Try this ( i just added one more line, the commented one):
#app.route("/sessions", methods=["GET","POST"])
def sessions():
userid = request.form.get("userid")
password = request.form.get("password")
if request.method == 'POST': #additional line
return request.form.get("userid"), request.form.get("password")
Updated answer reflects new comments
Found couple issues in your code:
HTML form is incorrect, you are using form in form
<form>
<form action="/sessions">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
You should change it to this
<html>
<body>
<h1>This is login page</h1>
<form action="{{ url_for('login') }}" method="POST">
<p>Username:</p>
<p><input type="text" minlength="8" name="username"required /></p>
<p>Password:</p>
<p><input type="text" name="password"/></p>
<input type="submit" value="Submit">
</form>
</body>
</html>
Notice changes, first there is only 1 form tag, then I use jinja2 engine to call the login in form.action, 2nd this login page handles serving login HTML when there is a GET request (initially opening this page) and for accepting form POST request with credentials.
Then I changed the routes to this:
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
user_name = request.form['username']
password = request.form['password']
print(user_name, password) # do something here?
return redirect(url_for('session'))
return render_template('login.html')
#app.route('/session')
def session():
return render_template('session.html')
Notice that now login accepts both methods, GET and POST, as mentioned before, GET is for serving HTML content and POST is for submitting form data. In the login endpoint I have a condition that checks, if it's a POST method request, then I extract credential details from request.form and after doing something (e.g. in that print() statementIreturn redirect(url_for('session'))`.
This is how you manage redirects from one page to another by clicking submit on one of a pages.
original answer that was incorrect
In Flask to redirect, you could you something like this:
from flask import url_for, redirect
#app.route('/sessions', methods['GET', 'POST']
def sessions():
# some code
return redirect(url_for('some.endpoint'))
This will redirect you to a specific endpoint that you will provide. In the docs there is more info about it.

Updating Form.intial does not change intial value in Django template

Goal
I want to retain the query when a search result renders. Here is an example where the search bar contains stackoverflow on the results page.
Failed Solutions
These are minimal code examples
# search_results.html
<form action="/search" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Search">
</form>
# views.py
...
class SearchView(TemplateView):
"""Search view"""
def form_valid(self, form):
"""redirect to the success url with url params"""
quoted_user_query = urllib.parse.quote_plus(form.cleaned_data['user_query'])
return HttpResponseRedirect(''.join([self.get_success_url(), quoted_user_query]))
def get_context_data(self. **kwargs):
context = super().get_context(**kwargs)
user_query = self.request.GET.get('q', None)
form.initial = {'user_query': user_query}
return context
def get_success_url(self):
"""append success url with search query"""
if not self.success_url:
raise ImproperlyConfigured('No success url for {}'.format((str(self))))
return ''.join([str(self.success_url), '?q='])
The first time I search in the browser, the template renders as expected. If I search foo the following is rendered
<form action="/search" method="post">
<input type="text" value="foo" name="search">
<input type="submit" value="Search">
</form>
But searching a second time doesn't change the string in the search bar. If I search bar after searching foo, the search bar's value does NOT change to bar as expected.
<form action="/search" method="post">
<input type="text" value="foo" name="search">
<input type="submit" value="Search">
</form>
What am I doing wrong? Below is the form code.
# forms.py
from django import forms
class SearchBar(forms.Form):
user_query = forms.CharField()
EDIT:
When I added {{ form.initial.user_query }} to the template, the expected value renders as text next to the search bar, but does NOT render in the search bar.
# search_results.html
{{ form.initial.user_query }}
<form action="/search" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Search">
</form>
bar
<form action="/search" method="post">
<input type="text" value="foo" name="search">
<input type="submit" value="Search">
</form>
I don't think you are getting any value with self.request.GET.get('q', None), because name of the input field is user_query in the forms. So try like this:
class SearchView(TemplateView):
"""Search view"""
def get_context_data(self. **kwargs):
context = super().get_context(**kwargs)
user_query = self.request.GET.get('user_query', None)
context['form'] = SearchBar(initial = {'user_query': user_query})
return context
Also change the form method from post to get ie <form method='get' action='/search'>
I found a clunky solution that creates a new instance of the form instead of updating the initial attribute
# views.py
...
class SearchView(TemplateView):
"""Search view"""
extra_context = {'form': SearchBar()}
def get_context_data(self. **kwargs):
context = super().get_context(**kwargs)
user_query = self.request.GET.get('q', None)
if user_query is not None:
context['form'] = self.form_class(data={'user_query': user_query})
return context
...

Django/Python: How to pass a variable from a form to a python script with POST method?

I'm getting this error when submit:
CSRF verification failed. Request aborted.
I've got this far following the documentation, but I don't fully understand it and it's definitely wrong. I just want to take a query word from my search box(form) and pass it to a python script as an argument. I'm new to Django and getting stuck on the easiest things.
In models.py:
class QueryForm(forms.Form):
query = forms.CharField(label='query',max_length=100)
I added this line to my urls.py
url(r'^results/$', 'tweemo.views.results'),
On my homepage where my search box is I have this code for my form:
<form action="/home/results/" method="post">
<label for="query">Search:</label>
<input id="query" type="text" name="query" value="{{ current_query }}">
<input type="submit" value="ok">
</form>
In views.py I added these two functions:
def get_query(request):
if request.method == 'POST':
form = QueryForm(request.POST)
if form.isvalid():
return HttpResponseRedirect('/thanks/')
else:
form = QueryForm()
return render(request, 'results.html', {'form': form})
def results(request):
return render_to_response('results.html',{'here':TwitterStream.objects.all() })
MY results.html contains just this:
<form action="/home/results/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit"/>
</form>
You must just add the {% csrf_token %} tag inside EVERY <form></form> tag which has method to be post in your template.
So the below markup should be corrected:
<form action="/home/results/" method="post">
{% csrf_token %}
<label for="query">Search:</label>
<input id="query" type="text" name="query" value="{{ current_query }}">
<input type="submit" value="ok">
</form>
Well the problem is that you are not passing the csrf token to the form , you need to pass the csrf token to the render function in order for it to be applied in the form . To accomplish this you need to associate the csrf token to the request.
def get_query(request):
if request.method == 'POST':
form = QueryForm(request.POST)
if form.isvalid():
return HttpResponseRedirect('/thanks/')
else:
form = QueryForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('results.html', args)
def results(request):
return render_to_response('results.html',{'here':TwitterStream.objects.all() })

How can I build multiple submit buttons django form?

I have form with one input for email and two submit buttons to subscribe and unsubscribe from newsletter:
<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>
I have also class form:
class NewsletterForm(forms.ModelForm):
class Meta:
model = Newsletter
fields = ('email',)
I must write my own clean_email method and I need to know by which button was form submited. But the value of submit buttons aren't in self.cleaned_data dictionary.
Could I get values of buttons otherwise?
Eg:
if 'newsletter_sub' in request.POST:
# do subscribe
elif 'newsletter_unsub' in request.POST:
# do unsubscribe
You can use self.data in the clean_email method to access the POST data before validation. It should contain a key called newsletter_sub or newsletter_unsub depending on which button was pressed.
# in the context of a django.forms form
def clean(self):
if 'newsletter_sub' in self.data:
# do subscribe
elif 'newsletter_unsub' in self.data:
# do unsubscribe
You can also do like this,
<form method='POST'>
{{form1.as_p}}
<button type="submit" name="btnform1">Save Changes</button>
</form>
<form method='POST'>
{{form2.as_p}}
<button type="submit" name="btnform2">Save Changes</button>
</form>
CODE
if request.method=='POST' and 'btnform1' in request.POST:
do something...
if request.method=='POST' and 'btnform2' in request.POST:
do something...
one url to the same view!
like so!
urls.py
url(r'^$', views.landing.as_view(), name = 'landing'),
views.py
class landing(View):
template_name = '/home.html'
form_class1 = forms.pynamehere1
form_class2 = forms.pynamehere2
def get(self, request):
form1 = self.form_class1(None)
form2 = self.form_class2(None)
return render(request, self.template_name, { 'register':form1, 'login':form2,})
def post(self, request):
if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
## do what ever you want to do for first function ####
if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
## do what ever you want to do for second function ####
## return def post###
return render(request, self.template_name, {'form':form,})
/home.html
<!-- #### form 1 #### -->
<form action="" method="POST" >
{% csrf_token %}
{{ register.as_p }}
<button type="submit" name="htmlsubmitbutton1">Login</button>
</form>
<!--#### form 2 #### -->
<form action="" method="POST" >
{% csrf_token %}
{{ login.as_p }}
<button type="submit" name="htmlsubmitbutton2">Login</button>
</form>
It's an old question now, nevertheless I had the same issue and found a solution that works for me: I wrote MultiRedirectMixin.
from django.http import HttpResponseRedirect
class MultiRedirectMixin(object):
"""
A mixin that supports submit-specific success redirection.
Either specify one success_url, or provide dict with names of
submit actions given in template as keys
Example:
In template:
<input type="submit" name="create_new" value="Create"/>
<input type="submit" name="delete" value="Delete"/>
View:
MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
success_urls = {"create_new": reverse_lazy('create'),
"delete": reverse_lazy('delete')}
"""
success_urls = {}
def form_valid(self, form):
""" Form is valid: Pick the url and redirect.
"""
for name in self.success_urls:
if name in form.data:
self.success_url = self.success_urls[name]
break
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
"""
Returns the supplied success URL.
"""
if self.success_url:
# Forcing possible reverse_lazy evaluation
url = force_text(self.success_url)
else:
raise ImproperlyConfigured(
_("No URL to redirect to. Provide a success_url."))
return url
I know this is old, but some of the answers are, to say the least, brief, and they do not address a common case where the form is not a django form.
This solution was inspired by this blog post. It relies on using a view class that is derived from django.views.generic.edit.FormMixin, e.g. CreateView, UpdateView or DeleteView. These provide the get_success_url method which exposes the button name in request
html
<html>
<body>
<form method="post">
<div>
<label> <input type="radio" name="select-type" value="A">Type A</label>
</div>
<div>
<label> <input type="radio" name="select-type" value="B">Type B</label>
</div>
<div>
<input type="submit" value="Use selected">
</div>
<div>
<input type="submit" name="no-selection" value="None of the above">
</div>
</form>
</body>
</html>
views.py
from django.views.generic import UpdateView
class GetType(UpdateView):
def get(self, request):
return render(request, 'get_type.html', {})
def post(self, request):
button = self.get_success_url()
print(button)
def get_success_url(self):
if 'no-selection' in self.request.POST:
return 'none selected'
return ''

Categories