I am trying to get the Flask WTF form to read longitude and latitude, but I can't find the proper form field for it. I found some examples where FloatField is used successfully, but the example are really old and I presume there have been changes in the WTF forms.
Here is the Form class I am using:
class GetFieldForm(Form):
field_name = StringField(Designation')
field_latitude = FloatField(u'Latitude', default=-30, validators=[InputRequired()], description='48.182601')
field_longitude = FloatField(u'Longitude', default=150,
validators=[InputRequired()], description='11.304939')
submit = SubmitField(u'Signup')
Passing the values from the form to the Google Maps:
#frontend.route('/demo')
def demo():
field_form = GetFieldForm()
if field_form.validate_on_submit():
flash('Hello, {}. You have successfully signed up'
.format(escape(field_form.name.data)))
field_latitude = field_form.field_latitude.data
field_longitude = field_form.field_longitude.data
mymap = Map(
identifier="view-side",
lat=field_latitude,
lng=field_longitude,
zoom=18,
style="height:720px;width:720px;margin:0;", # hardcoded!
markers=[(field_latitude, field_longitude)],
maptype='SATELLITE'
)
return render_template('demo.html', mymap=mymap, field_form=field_form)
With the following Jinja2 template:
<div class="container-fluid">
<div class="row-fluid">
<div id="map" class="col-md-7">
{{mymap.html}}
</div>
<div class="col-md-5">
<div class="panel panel-default">
<!-- Panel Title -->
<div class="panel-heading">
<h2 class="panel-title text-center">Locate Your Field <span class="glyphicon glyphicon-map-marker"></span></h2>
<div class="panel-body">
{% if request.args.get('legacy') -%}
{{wtf.quick_form(field_form, novalidate=True)}}
{%- else -%}
{{field_form|render_form()}}
{%- endif %}
</div>
</div>
</div>
</div>
The problem is, that the form doesn't allow me to pass longitude and latitude as floats:
Versions I am using:
Flask 0.12
Flask-WTF 0.14.2
Flask-GoogleMaps https://github.com/rochacbruno/Flask-GoogleMaps
EDIT: Got a hint that I the error may have something to do with FLASK-Bootstrap>
The problem is Flask-Bootstrap, that you seem to be using.
https://github.com/mbr/flask-bootstrap/blob/master/flask_bootstrap/forms.py#L97-L99
It overrides the float type to use "number" as input type, which is
not quite right there, since "number" in html5 is limited to integers
if the step argument is not provided. So you have to set the step
attribute on your input field, though I don't know how to do that with
Flask-Bootstrap. Preferably something like step="0.000001" should
suffice.
But how would I pass the step parameter is beyond me...
Found a solution.
Instead of generating the form like this:
{{field_form|render_form()}}
do this:
{{wtf.quick_form(field_form, novalidate=True)}}
Related
I have a CRUD application where wtforms is being used to populate a series of forms with a 'for' loop to allow users to edit existing data in the DB. I'm using "value=row.XXX" to pre-populate the form with existing data from the DB as a default. This works well for normal StringFields, but doesn't work for SelectField. Can anyone help!?
Example html below. The form_edit.group is a SelectField. Annoyingly, when displayed in the form, it defaults to the first item in the 'choices' list rather than the previously chosen data (value=row.group doesn't work as it does for StringFields). This means that when the user comes to resubmit the form it defaults to this first item.
<div class="form-group col-sm-6">
{{ form_edit.description.label }}
{{ form_edit.description(class="form-control", value=row.description) }}
{% for error in form_edit.description.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
<div class="form-group col-sm-6">
{{ form_edit.group.label }}
{{ form_edit.group(class="form-control", value=row.group) }}
{% for error in form_edit.group.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
</div>
<div class="row">
<div class="form-group col-sm-6">
{{ form_edit.qty.label }}
{{ form_edit.qty(class="form-control", value=row.qty) }}
{% for error in form_edit.qty.errors %}
<span style="color: red;">[{{ error }}]</span>
Forms:
class Areas_form(FlaskForm):
hidden_id = HiddenField('Area id')
description = StringField('Description',validators=[DataRequired()])
group = SelectField('Group',validators=[DataRequired()],choices=['Ext(Am) Wall','Ext(Gnd) Wall','Roof(Am)','Flr Slab','Flr(Am)'])
qty = FloatField('Quantity', validators=[DataRequired(message='must be a number')], default=float(1))
lth_a = FloatField('Length a', validators=[DataRequired(message='must be a number')])
lth_b = FloatField('Length b', validators=[DataRequired(message='must be a number')])
assembly = SelectField('Assembly',validators=[DataRequired()], choices=[])
dev_nth = FloatField('Deviation from North', validators=[InputRequired(message='must be a number')])
ang_hor = FloatField('Angle from horizontal', validators=[InputRequired(message='must be a number')])
submit = SubmitField('Submit data')
Example row:
When I press "edit" the following form comes up. The "group" "Flr Slab", has defaulted back to the first item in the choices list - "Ext(Am) Wall".
By contrast the "description" field has pulled "Floor 1" from the database.
Update your SelectField difinition in class Areas_form(FlaskForm): as follows:
group = SelectField('Group',validators=[DataRequired()],choices=[(1,'Ext(Am) Wall'),(2,'Ext(Gnd) Wall'),(3,'Roof(Am)'),(4,'Flr Slab'),(5,'Flr(Am)')])
where we assign the value option as well as the appeared text, and finally, then in your code after form submission, you get the value as regular column fields
Notice, you will use numbers 1,2,3,4, or 5 as a mapping for your choices in select, which would be better.
Adding upon commit
In order to set the default value update
{{ form_edit.group(class="form-control", value=row.group) }}
to
{{ form_edit.group(class="form-control", value=row.group.data) }}
if it does not work, check that data type of type(row.group.data) in python, if it is string type, update the group column difiniation to:
group = SelectField('Group',validators=[DataRequired()],choices=[('1','Ext(Am) Wall'),('2','Ext(Gnd) Wall'),('3','Roof(Am)'),('4','Flr Slab'),('5','Flr(Am)')])
In case, we force to use integer value, add coerce=int to the end of my first suggestion before additions as follows:
group = SelectField('Group',validators=[DataRequired()],choices=[(1,'Ext(Am) Wall'),(2,'Ext(Gnd) Wall'),(3,'Roof(Am)'),(4,'Flr Slab'),(5,'Flr(Am)'),coerce=int])
looking for to hearing from you :)
Good Luck
I have looked online and found that I can use macros to render different content to my modal. Yet there is something missing in my code that prevents it from getting updated and I'm not sure of what exactly.
#app.route("/candidates")
def candidate_fun():
mapping={
"001":"Bangalore",
"002":"Delhi",
"003":"Chennai",
"004": "Mumbai",
"005":"Kolkata",
"006":"Hyderabad"
}
myclient=pymongo.MongoClient(uri)
mydb = myclient["codefundo"]
mycol=mydb['cand_reg']
result=[]
for x in mycol.find():
obj=NewsSearch()
# import pdb; pdb.set_trace()
t=dict(x)
t['a'],t['b'],t['c']=obj.news_candidate(search_term=str(x["First Name"].lower()+" "+x["Last Name"].lower()+ " election"))
# t['News']=str(a+". "+b+". "+c)
result.append(t)
# result.append({'News':obj.news_candidate(search_term=str(result["First Name"]+" "+result["Last Name"]+" election"))})
return flask.render_template("candidate.html",result=result,mapping=mapping)
While the python code isn't of significance, I have provided it to show that I am passing a list result of type dict.
HTML Jinja
<!--MODAL PART-->
{% macro render_modal(a,b,c) -%}
div class="modal-body">
<p>{{a}}</p>
<p>{{b}}</p>
<p>{{c}}</p>
</div>
{%- endmacro%}
<!-- Jinja to make a call -->
{% for key in result %}
<div class="col-6">
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#exampleModalLong">Info</button>
{{render_modal(key['a'],key['b'],key['c'])}}
<!-- Just to test if the value sent is received {{key['a']}} -->
</div>
{% endfor %}
It returns the same data over the modal box for all entries being passed. I want for it to show me the specific values - key[a], key[b], key[c] for every new key in the iteration.
Similar question here: Passing a row ID in a table to a modal in flask (python)
You need to set an id on your modal and refer to that specific id in your button to identify a specific modal. In order for each modal to render different inputs, you need to set different ids for each button-modal group.
In your case, add a unique identifier for each key object in addition to your data entries, e.g.
# in the routes
t['id'] = # unique id identifying the modal
t['a'] = ...
t['b'] = ...
# etc.
Then in the for-loop that calls the modal macro, include the unique id in some way on the data-target attribute of your button:
{% for key in result %}
<div class="col-6">
<button type="button" data-target="#exampleModalLong{{ key.id }}" class="btn btn-info" data-toggle="modal">
Info
</button>
{{ render_modal(key) }}
</div>
{% endfor %}
Use the exact same name you used for data-target for the id of your modal div:
{% macro render_modal(key) -%}
<div class="modal-body" id="exampleModalLong{{ key.id }}">
<p>{{ key.a }}</p>
<p>{{ key.b }}</p>
<p>{{ key.c }}</p>
</div>
{%- endmacro%}
Note that this will inject a lot of HTML into your code if you have a lot of entries in your for-loop. As mentioned in the Stack Overflow post linked at the top, you can consider defining just one modal, and use AJAX to change the modal content.
I'm fairly new to Django and I'm working on a page that takes in user information. If all of the information is correct, it will proceed to the next page. However, if the user does not provide all given info, it will to refresh the page. My problem is that there are quite a bit of fields the user has to fill out and if the person misses any fields, I don't want them to have to re-type everything out. So my workaround for it is that in the views.py I created a dictionary and it populates it with the input names in the template. However, when I go to run the code, it gives me an error saying that the values in my dictionary do not exist. I'm now thinking that my dictionary is not actually accessing any of the template values.
Here is my template:
<!DOCTYPE html>
{% extends "Checklist/base.html" %}
{% block main_content %}
{% load static %}
<html>
<body>
<form action="{% url 'Checklist:signin_check' %}" method="post">
{% csrf_token %}
<ul style="list-style-type:none">
<li>
<label for="driver_first_name">Driver First Name:</label>
<input type="text" name="driver_first_name" value="" id="driver_first_name">
</li>
<li>
<label for="driver_last_name">Driver Last Name:</label>
<input type="text" name="driver_last_name" value="" id="driver_last_name">
</li>
<li>
<label for="driver_wwid">Driver WWID:</label>
<input type="text" name="driver_WWID" value="" id="driver_WWID" maxlength="8"
onkeypress="return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57">
</li>
<li>
<label for="co_driver_first_name">CO-Driver First Name:</label>
<input type="text" name="co_driver_first_name" value="" id="co_driver_first_name">
</li>
<li>
<label for="co_driver_last_name">CO-Driver Last Name:</label>
<input type="text" name="co_driver_last_name" value="" id="co_driver_last_name">
</li>
<li>
<label for="co_driver_wwid">CO-Driver WWID:</label>
<input type="text" name="co_driver_WWID" value="" id="co_driver_WWID" maxlength="8"
onkeypress="return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57">
</li>
<li>
<input type="submit" value="Continue">
</li>
</ul>
</form>
</body>
</html>
{% endblock %}
Here is the views.py:
def signin_check(request):
driver_info_model = Driver()
if request.method == "POST":
driver_info_form = Driver_Form(request.POST)
c = {'driver_first_name':driver_first_name, 'driver_last_name':driver_last_name,
'driver_WWID':driver_WWID, 'co_driver_first_name':co_driver_first_name,
'co_driver_last_name':co_driver_last_name, 'co_driver_WWID': co_driver_WWID,}
if driver_info_form.is_valid():
driver_info_form.save()
return render(request, 'Checklist/checklist.html')
template = loader.get_template('Checklist/signin.html')
return HttpResponse(template.render(c, request))
any feedback would be greatly appreciated. Thanks!
However, when I go to run the code, it gives me an error saying that
the values in my dictionary do not exist. I'm now thinking that my
dictionary is not actually accessing any of the template values.
From your views.py alone I'm guessing the exception you're running into is that you're assigning dictionary values that aren't defined. For example, in 'driver_first_name':driver_first_name, Python is looking for a variable named driver_first_name but you haven't defined it. The data you're looking for, as Justin alluded to, can be found in requests.POST.
One solution, while more verbose, illustrates what needs to be done:
def signin_check(request):
driver_info_model = Driver()
if request.method == "POST":
driver_info_form = Driver_Form(request.POST)
driver_first_name = request.POST.get('driver_first_name', '')
driver_last_name = request.POST.get('driver_last_name', '')
driver_WWID = request.POST.get('driver_WWID', '')
co_driver_first_name = request.POST.get('co_driver_first_name', '')
co_driver_last_name = request.POST.get('co_driver_last_name', '')
co_driver_WWID = request.POST.get('co_driver_WWID', '')
c = {'driver_first_name': driver_first_name,
'driver_last_name': driver_last_name,
'driver_WWID': driver_WWID,
'co_driver_first_name': co_driver_first_name,
'co_driver_last_name': co_driver_last_name,
'co_driver_WWID': co_driver_WWID, }
if driver_info_form.is_valid():
driver_info_form.save()
return render(request, 'Checklist/checklist.html')
template = loader.get_template('Checklist/signin.html')
return HttpResponse(template.render(c, request))
My problem is that there are quite a bit of fields the user has to
fill out and if the person misses any fields, I don't want them to
have to re-type everything out.
To address your second concern you'll need to deal with your HTML template. Your input fields have a value of "", so any value you pass through your context is not going to reach any of them. Luckily you're on the right path and you're quite close, so all you need to do is fill those values in. For example:
<li>
<label for="driver_first_name">Driver First Name:</label>
<input type="text" name="driver_first_name" value="{{ driver_first_name }}" id="driver_first_name">
</li>
Note that {{ driver_first_name }} is referencing the driver_first_name that's being passed into the context.
Im not 100% sure as i'm fairly new to Django myself, but from what i've done previously you can get the POST data from the request that is passed in, like this:
request.POST['driver_first_name']
which raises an error if no data is present or from
request.POST.get('driver_first_name', 'optionaldefaultvalue')
which returns None if no data is present in the specified field, or an optional default.
It might also be easier to do what you are after with django's inbuilt forms
I'm trying to loop through a database and output the results in a django template. I got all that working but it outputs every item as the following in the html:
[u'AMD', u'A10-7700K, 3,4 GHz (3,8 GHz Turbo Boost) FM2+ processor']
[u'\n 3.400 MHz\xa0\n ', u'\n 4 cores\xa0\n ', u'\n FM2+\xa0\n ']
For the record. I want it to output as a normal string without the unicode. I tried a bunch of things but none of it seems to work. I would write down all the things I've tried but I honestly can't even keep track of all of it.
I got the following django files, I'll only write down the relevant pieces:
views.py:
def processoren(request):
processoren = Processoren.objects(categorie__contains='Processor')[:10]
#processoren = json.dumps(list(processoren)
return render_to_response('processoren.html', {'Processoren': processoren},
context_instance=RequestContext(request))
models.py:
from django.db import models
from mongoengine import *
from APc.settings import DBNAME
connect(DBNAME)
class Processoren(Document):
categorie = StringField(max_length=120)
naam = StringField(max_length=500)
subnaam = StringField(max_length=500)
info = StringField(max_length=500)
stock = StringField(max_length=500)
enter code hereprijs = StringField(max_length=120)
processoren.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container">
<div class="col-md-4 col-lg-2">
</div>
<div class="col-md-8 col-lg-10">
<div class=" top-margin">
<h1>Processoren</h1>
{% for processor in Processoren %}
<div class="list-group">
<div class="list-group-item">
<div class="row-picture">
<img class="square" src="http://lorempixel.com/56/56/people/1" alt="icon">
</div>
<div class="row-content">
<h4 class="list-group-item-heading">{{ processor.naam }}</h4>
<p class="list-group-item-text">{{ processor.info }}</p>
<p class="list-group-item-text pull-right">{{ processor.prijs }}</p>
<p class="list-group-item-text pull-right">{{ processor.stock }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
I tried to simply just put str() after processor.naam for example but that doesn't work either. What does work is adding 0 after processor.naam but then I of course only get the first index which would be "AMD". Any help would be appreciated.
This is nothing to do with Unicode. You have a list of items, you need to iterate through them.
{% for name in processor.naam %}{{ name }}{% endfor %}
Not being familiar with MongoEngine in regards to Django, it's fairly simple to convert your unicode values to strings, which will hopefully get you by for the time being until you can address the root of the problem.
objects = Processoren.objects.filter(categorie__contains='Processor')[:10]
processoren = [str(p.naam) for p in objects]
Again, I don't know what methods are available on the query set using that engine, so I've avoided using values_list in this case. Wasn't sure which property you needed to output either so I just used naam
I have been working with a Django form that can generate a number of fields dynamically according to the parameters passed in, as I have learnt from SO, like this:
class Review_Form(forms.Form):
def __init__(self, *args, **kwargs):
sentences = kwargs.pop('sentences')
super(Review_Form, self).__init__(*args, **kwargs)
counter = 1
for q in sentences:
self.fields['review' + str(counter)] = forms.CharField(label='Review' + str(counter), required=False)
counter += 1
As for the corresponding html, I pass the each field separately into contest['block'], where block is a list of dictionaries, with key value pair indicating the ith field of the form and the corresponding items I need.
So the html is as following:
<form action="{% url 'done_review' title%}" method="post">
<div class="container">
<div class="row">
{% for b in block %}
<div class="8u">
<p> {{b.sent}} </p>
</div>
<div class="4u">
<input class="front_form-control" value="{{b.text}}" type={{b.field}}
</div>
</div>
{% csrf_token %}
{% endfor %}
</div>
<div class="container">
<div class="row">
<div class="12u">
<button class="btn btn-lg btn-info" type="submit" value="Submit">Done Review
</button>
</div>
</div>
</div>
{% csrf_token %}
</form>
Then, unfortunately, the form is not valid after I submit it. I tried to test it by printing the errors in views.py, like the following:
if form.is_valid():
# do something
else:
print form.errors, 'here1'
print form.non_field_errors(), 'here2'
field_errors = [(field.label, field.errors) for field in form]
print field_errors, 'here3'
It prints out like this:
here1
here2
[('Review1', []), ('Review2', []), ...many more... ('Review38', [])] here3
I really don't understand why the form is not valid and I have got stuck here for days and googled everywhere. Hope someone could help me here.
Many thanks!!!
Finally, the problem is solved.
This happens because the form is unbound, because of one of my careless mistakes:
form = Review_Form(sentences=sents)
instead of what it should be:
form = Review_Form(request.POST, sentences=sents)
I answered this because I think this is probably useful for other new developers like me.
Read more on unbound and bound forms, if you like, from here: Django form API