Flask hidden input doesn't get set in template - python

So I'm trying to pass a value from a Jinja2 template back to my Python code. I'm trying to do this with a hidden input. My form class is this:
class TrueOrFalseForm(flask_wtf.FlaskForm):
choice = RadioField(choices=[('True', 'TRUE'), ('False', 'FALSE')], validators=[validators.InputRequired()])
hidden = HiddenField()
submit = SubmitField('Submit')
And my form is this:
<form autocomplete="off" action="" method="post">
{{ form.hidden_tag() }}
<div style="text-align: center">
<div style="display: inline-block">
{{ form.choice }}
{{ form.hidden(value="{{ result }}") }}
{{ form.submit(class_="btn btn-primary btn-lg") }}
</div>
</div>
</form>
result is a string that I'm passing when rendering the template.
When checking the value of form.hidden.data, though, it comes back as ''. The tag also renders as <input id="hidden" name="hidden" type="hidden" value="">.
I've also tried doing value={{ result }} instead of value="{{result}}" but that makes Jinja throw a TemplateSyntaxError.
Any idea on how to do this?
EDIT:
I'm overwriting result every time I call the function.
This is my route function:
#app.route('/', methods=['GET', 'POST'])
def home():
form = forms.TrueOrFalseForm()
x = random.randint(-100, 100)
y = random.randint(-100, 100)
statement_str = generate_statement_string(2)
tree = BinTree.build_tree(statement_str)
statement_result = BinTree.solve_tree(tree, x, y) # result gets overwritten here
if form.validate_on_submit():
if not flask_login.current_user.is_anonymous:
# same as the else, except with some sql, not relevant
else:
if form.choice.data == form.hidden.data:
flask.flash('Correct!')
else:
flask.flash('Incorrect!')
return flask.render_template('home.html', x_value=str(x), y_value=str(y), statement=statement_str,
result=str(statement_result), form=form)

{{ form.hidden(value="{{ result }}") }} is already in templating syntax with the outer double curly brackets. Therefore, you should just be able to plainly write the result variable, like this: {{ form.hidden(value=result) }}
EDIT
Replace {{ form.hidden_tag() }} with {{ form.csrf_token() }} as well as doing what is in my original answer.
You may also have to instantiate the form with form = forms.TrueOrFalseForm(request.form). Some forms behave weirdly if you don't do that.

Since you're using {{ form.hidden_tag() }} in your template, you do not need to explicitly render the hidden form field. It will be included in the hidden_tag() call.
You can set the value of the hidden field in your views before rendering the template.
views.py
form.hidden.data = result
return render_template("index.html",form=form)
index.html
<form autocomplete="off" action="" method="post">
{{ form.hidden_tag() }}
<div style="text-align: center">
<div style="display: inline-block">
{{ form.choice }}
{{ form.submit(class_="btn btn-primary btn-lg") }}
</div>
</div>
</form>

My proposal is:
<input type="hidden" id="locphoto" value="{{ mbrs.photoName|safe }}" />
Previous answer are correct but I think they need some correction putting safe in variable jinja:

Related

Adding SelectQueryField Id attribute in Jinja2

I'm trying to assign Id attribute to the SelectQueryField in Jinja.
The problem is Jinja don't render variable in double curly brackets.
<form method="post" class="form form-inline" >
{{ form.opcje(class="form-control form-select", id="{{user.id}}" ) }}
</form>
output:
<select class="form-control form-select" id="{{user.id}}" name="opcje"><option selected="" value="__None">Wybierz cechę</option><option value="1">Sklepy</option><option value="2">Niemcy</option><option value="3">Holandia</option></select>
Try:
<form method="post" class="form form-inline" >
{{ form.opcje(class="form-control form-select", id=user.id ) }}
</form>
You can use variables inside the first set of {{...}} freely.

List item template Django

I'm dealing creating a template on Django to show a list of items with 2 buttons that make actions.
My form class it's:
class AppsForm(forms.Form):
def __init__(self, *args, **kwargs):
policiesList = kwargs.pop('policiesList', None)
applicationList = kwargs.pop('applicationList', None)
EC2nodesList = kwargs.pop('amazonNodesList', None)
super(AppsForm, self).__init__(*args, **kwargs)
self.fields['appsPolicyId'] = forms.ChoiceField(label='Application Policy', choices=policiesList)
self.fields['appsId'] = forms.ChoiceField(label='Application', choices=applicationList)
self.fields['ec2Nodes'] = forms.ChoiceField(label='Amazon EC2 Nodes', choices=EC2nodesList)
Now, I do the form with:
<form method="post" action="" class="form-inline" role="form">
<div class="form-group">
{% for field in form %}
{ field.label }}: {{ field}}
{% endfor %}
</div>
{% csrf_token %}
<input type="submit" class="btn btn-default btn-success" name="deployButton" value="Deploy"/>
<input type="submit" class="btn btn-default btn-danger" name="undeployButton" value="Undeploy"/>
And the result it's:
Application Policy - Choicefield ; Application - Choicefield ; Amazon EC2 Nodes - Choicefield [Button Deploy] [Button Undeploy]
And what I'm looking for it's a way to render the form and show the list like this:
Application Policy - Choicefield ; Application - Choicefield [Button Deploy] [Button Undeploy]
Amazon EC2 Nodes - Choicefield [Button Deploy] [Button Undeploy]
<more items if I add them in forms.py...>
How I can get the proper way to render like that?
Thanks and regards.
You just need to change the code a bit is all:
{% for field in form %}
{ field.label }}: {{ field}}
<input type="submit" class="btn btn-default btn-success" name="deployButton" value="Deploy"/>
<input type="submit" class="btn btn-default btn-danger" name="undeployButton" value="Undeploy"/>
<br />
{% endfor %}
So this will create a new line for each of the field.label and field variables with their own button. One thing to caution against though, if you try and assign ID's to the buttons they will have to be different or you'll get errors. Also, submission may be a bit weird with code such as this but it depends on the rest of your application. Either way, this will give you the desired format.

Python Flask endless redirect loop 302

I have currently an issue where one of my pages in flask falls into an endless redirect loop:
I have already so many routes and methodes and had never a problem with this. I also have no idea how to solve it, here is the function / route which has this problem (Its a simple mail function, couldnt even test it):
#app.route('/kontakt/', methods=["GET", "POST"])
def kontakt_send():
form = KontaktMailForm()
if form.validate_on_submit():
if form.check.data == 9:
simplemail.Email(
from_address = form.absender.data, #request.form["absender"],
to_address = u"email#email.de",
subject = u"Nachricht - Kontaktformular von " + form.name.data,
message = form.nachricht.data #request.form["nachricht"]
).send()
flash("Nachricht erfolgreich versandt")
return redirect(url_for('kontakt_send'))
else:
flash("Was ist 4+5?")
return redirect(url_for('kontakt_send'))
else:
flash("Alle Felder muessen ausgefuellt werden")
return redirect(url_for('kontakt_send'))
return render_template('kontakt.html', form=form)
I dont even know which data is relevant to solve this issue, but here is the form from the html template:
<form id="kontaktform" method="POST" enctype="multipart/form-data" action="{{ url_for('kontakt_send') }}">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.name.label }} <span class="star"> * </span>
{{ form.name(size=30, class = "form-control", placeholder="z.B. Markus Müller") }}
</div>
<div class="form-group">
{{ form.absender.label }} <span class="star"> * </span>
{{ form.absender(class = "form-control", placeholder="z.B. markus.müller#gmx.de") }}
</div>
<div class="form-group">
{{ form.nachricht.label }} <span class="star"> * </span>
{{ form.nachricht(size=500, class = "form-control", placeholder="z.B. Ihre Nachricht an uns") }}
</div>
<div class="form-group">
{{ form.check.label }} <span class="star"> * </span>
{{ form.check(class = "form-control", placeholder="z.B. 9") }}
</div>
<div class="">
<button type="submit" class="btn mybtn"> Senden </button>
</div>
</form>
EDIT:
Remiving the second return redirect(url_for('kontakt_send')) from the else solved the issue, but everytime I load the page it shows me the flash message eventhough I am not submitting the form, how is this possible? It submits the form by reloading the page
validate_on_submit checks two things:
Is the request a POST?
Does the post body validate as the specified form?
If either of these is false, the else block runs and generates the flash message. Since the first check will be false for all GETs, you'll receive the flash message on every page load that isn't a form submission (this is also why you has the redirect loop). The second one will be false anytime the form doesn't validate, thus leading to the flash message again.
All of your if/else blocks lead to flash messages. That's why you get one on every request.

Display form input with Django

So basically I want to make a simple form I can enter text and the after I hit submit, see the text.
Here is my forms.py:
class Search(forms.Form):
search = forms.CharField()
Here is my views.py:
def search(request):
context = RequestContext(request)
if request.method == 'POST':
search = Search(data=request.POST)
if search.is_valid():
ticker = search.save()
ticker.save()
success = True
else:
print search.errors
else:
search = Search()
return render_to_response('ui/search.html', {"search":search}, context)
Here is the html form that you use to type in (I'm using bootstrap for styling purposes):
<form class="navbar-form navbar-right" role="search" action="/search/" method="post" name="tick">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter stock symbol">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And finally, I want the text entered in the form to be displayed on "search.html" which looks like this currently:
{% extends 'ui/base.html' %}
{% block title %} search {% endblock %}
{% block body_block %}
<br>
<p>test</p>
{{ form.search.data }} <!--I'm pretty sure this is not correct -->
{% endblock %}
Anyone know how I can do this? Thanks.
Your form name is search.
To render the value with modern django, you need to call the value method of the field, therefore your template should look like the following:
{{ search.search.value }}
Your template is wrong, as you suspect.
It is looking for a context variable named "form", but you have given it a context dictionary with a key named "search".
Also, "data" is the argument that you use to build up your Search object (correctly), but when you want to extract the user's input from it, you should use the field names instead, and you need to call value() on them in order to get the bound value. So, to get the contents of the text field called search, you should use search.search.value.
Try changing the line
{{ form.search.data }}
to
{{ search.search.value }}

Django render form with data when not validated

I wrote this contact form with some help from the Django docs:
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['name#e-mail.com']
if cc_myself:
recipients.append(sender)
m = '%s\n\n-----------------\n%s' % (message, name)
from django.core.mail import send_mail
send_mail(subject, m, sender, recipients)
return HttpResponseRedirect('/kontakt/tack/')
else:
form = ContactForm()
return render(request, 'contact/index.html', {
'form': form,
})
The problem is that if the form doesn't validate it returns an empty form. That could be a big annoyance for someone that have written a long message but forgot to put his name in or something.
I've fixed that by change the the code below to last else: to:
try:
form = ContactForm(form.cleaned_data)
except UnboundLocalError:
form = ContactForm()
I needed to try-statement for the first rendering of the page when no form.cleaned_data yet exist. This works, but it seems like a rather ugly hack.
Is there some standard way to use the text from previous fill in when re-rendering the form without my ugly try-except solution?
Template on request
{% block content %}
<div id="contact-generic-container">
<p>Lorem ipsum (not really, but ain't relevant).</p>
</div> <!-- #contact-generic-container -->
<div id="contact-form" class="clearfix">
<br/>
<h2>Kontakta oss!</h2>
<form action="/kontakt/" method="post">
{{ form.non_field_errors }}
<fieldset class="text">
{% csrf_token %}
<div class="field-wrapper">
<label for="id_name">Namn:</label>
{{ form.name }}
{{ form.name.errors }}
</div>
<div class="field-wrapper">
<label for="id_sender">E-post:</label>
{{ form.sender }}
{{ form.sender.errors }}
</div>
<div class="field-wrapper">
<label for="id_subject">Ämne:</label>
{{ form.subject }}
{{ form.subject.errors }}
</div>
</fieldset>
<fieldset class="text">
<div class="field-wrapper">
<label for="id_message">Meddelande:</label><br/>
{{ form.message }}
{{ form.message.errors }}
</div>
<div class="field-wrapper">
<label for="id_cc_myself">Kopia till mig själv:</label>
{{ form.cc_myself }}
{{ form.cc_myself.errors }}
</div>
<input type="submit" value="Skicka" />
<fieldset class="text">
</form>
</div>
{% endblock %}
Here's a simple way to always either init the form with the POST data, or nothing:
def contact(request):
form = ContactForm(request.POST or None)
if request.POST and form.is_valid():
Then remove your else block.
The form will always have data in it, and won't throw an error if it's just a GET.
Since I'm using some Python trickery, allow me to explain.
Python supports and/or operator in expressions.
When evaluting an or python will stop when the first value returns a truthy value.
When evaluating an and, Python will stop if the first condition returns false.
So, when we init the form, we ask Python to assign either the value of request.POST (if it's true), or None, if request.POST is false (which it will be if it's empty). This inits the form with the values from request.POST correctly when there's a POST, but None otherwise.
In our if statement, if request.POST is false (which it will be if request.POST is empty), Python stops there and never calls form.is_valid(), so we don't have to worry about validation running if the POST isn't present.
Neat huh?

Categories