WTF Bootstrap Quick Form how to render HTML - python

Hi there I have to use one unique HTML page to display a few fields that will be populated with some data retrieved from a csv file.
I want to use the WTF quick form to pass all the fields together to the HTML page, since I won't know the field names, because they can be retrieved from different csv files(they will be equivalent to the column header of the csv).
The only problem is that I want them to be displayed in two columns (div), so half fields in one colums, half in the other, while quick form will show them in a single vertical list.
How can I sort this out in the easiest way? any attribute to add to the quick form for the layout?
I have tried the following using wtf.form_field, but in this way I must know the name of each field, and I will have to create one HTML page for each CSV file, while I want to have 1 HTML page with quick form, but I can't have the fields displayed in two columns that way.
<div class="row">
<div class="col-md-6">
{{ wtf.form_field(form.COD_SPORTELLO) }}
{{ wtf.form_field(form.QU_CAP) }}
{{ wtf.form_field(form.QU_CAP_INTER) }}
{{ wtf.form_field(form.CAUSALE) }}
{{ wtf.form_field(form.ONERI_RATE_VAL) }}
{{ wtf.form_field(form.FLAG_ANTIRIC) }}
{{ wtf.form_field(form.FLAG_VIG) }}
</div>
<div class="col-md-6">
{{ wtf.form_field(form.COD_RAPPORTO) }}
{{ wtf.form_field(form.QU_CAP_VALUTA) }}
{{ wtf.form_field(form.DATA_SCADENZA) }}
{{ wtf.form_field(form.ONERI_RATE) }}
{{ wtf.form_field(form.QU_INTER_VALUTA) }}
{{ wtf.form_field(form.FLAG_AR) }}
</div>
</div>
I think it's a bit tricky because even if I pass some parameter to the quick form like horizontal_columns for instance ( Must be a 3-tuple of column-type, left-column-size, right-column-size), it will create a second column, but it will display the fields only one column still, so somehow I have to tell him that I want half of the fields on one column and half on the other column (div).
I can't use form_field and list each fileld name cause I won't know the field names.

The fields can be assigned a class directly from the template. If you know what bootstrap classes you need then you call it with the field with a keyword argument class
As explained in this answer
Add a css class to a field in wtform

Related

wtforms CRUD - set default in SelectField

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

Is it possible to send two dataframes to my html (flask)?

So my html page receives a pandas dataframe.
return render_template('example.html', tables=[data_frame.to_html(classes='data')], titles=dataframe.columns.values)
and my html page displays it:
{% for table in tables %}
{{titles[loop.index]}}
{{ table|safe }}
{% endfor %}
What I want to do is display two separate dataframes in my html page. How can I do this?
For example:
If I have dataframes df1 and df2,
in the html page I want to display them after some text.
show df1
<h2> some text </h2>
show df2
Since render_template accepts dictionaries, you can pass a Dict object named context or whatever to the "render_template" function with "table" and "title" keys.
And then in your Jinja you can access these keys by context.table and context.title.
Example:
def my_function(request):
...
get your dataframe
...
context = {"tables":[data_frame.to_html(classes='data')],
"titles" : dataframe.columns.values,
}
return render_template('template.html', context=context)
This can be done easily in render_template
Your code can be changed like this:
return render_template('example.html',tables= [data_frame1.to_html(classes='data'),data_frame2.to_html(classes='data')],
titles=['na','FirstTable','SecondTable'])
As you can see , you can add more than one dataframe in tables.
Now in Jinja, you can simply loop through each table(dataframe) and display
{% for table in tables %}
{{ titles[loop.index] }}
{{ table|safe }}
{% endfor %}
Refer the below image for your reference:

Get model attributes without making them required for modelform_factory?

I've got a modelform_factory which works perfect for what I need.
I call it like this:
dep_formset = modelformset_factory(
Dependent,
fields=('has_medical', 'med_group_id'),
max_num = dep_count
)
As you might guess, Dependent has additional fields that I want to use simply for display purposes (first_name and last_name respectively) I want to show the first_name and last_name of the dependent person - but have it be simply for display, not edit.
If I add 'first_name' and 'last_name' to the fields in the above, I can then access them in my template - but the form fails against .is_valid() because I'm displaying them simply as text and not as an input, so they're not being POST'ed
Is there some clever way to get access to the first_name and last_name of the dependent objects without adding them to fields for the formset_factory?
The template looks like this (partial snippet so you can see what I'm trying to do with the first_name, last_name):
{% for form in dep_formset %}
{{ form.id }}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="g">
<h4>{{ form.first_name.value }} {{form.last_name.value}}</h4>
</div>
<div class="g dependent-option">
<div class="g-1-4 dependent-option-check">
{% if form.has_medical %}
Based on provided information it looks like the formset is tied to an instance which you can access in template:
{{ form.instance.first_name }}

Django form template customization

New to django (and in general python). I'm trying to customize one of my forms a bit and would like to know the best way to do this.
Take for example the following, a form with 3 fields, two fields for weight entry and one for a target date.
class BasicFitnessGoalForm(forms.ModelForm):
class Meta:
model = BasicFitnessGoal
fields = ('currentWeightKg','targetWeightKg','targetDate')
widgets = {
'targetDate': forms.DateInput(attrs={'class':'formdatepicker'}),
}
labels = {
'currentWeightKg' : "Current Weight",
'targetWeightKg' : "Goal Weight",
'targetDate' : 'Goal Date'
}
I want to be able to display this form in my templates using something like goalForm.as_p() which generates html like the following:
<p>
<label></label><input><input>...
What I am looking to do is on the weight fields insert an extra element after the input tags and customize the text and css classes. So I end up with something like this:
<p>
<label>Current Weight</label><input type=Number...><span class="customCss">Kg (or text I enter</span>
</p>
So is there anyway to accomplish this inside the model class? I know I could do this with javascript or by looping through the fields in the template instead of using the form.as_p tag. But I want to reuse this so it's cleanest if I can create a method to output the desired html wherever I want to use it.
I've seen some examples where you can set a method on the form like as_foobar where the self.html_output is returned. But I see that that only allows to specify values like "normal_row", "error_row" etc. I want to code a custom template for this form and return the html from a method on the model that I can then access from a template. (or override the as_p method for this model to return custom html depending on field).
Hopefully that makes sense.
Using a custom widget as suggested in the comment is one option, another is to loop through the fields manually.
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
{% if field.id_label = id_currentWeightKg" %}
<span class="customCss">Kg (or text I enter</span>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="Submit" />
</form>
For additional information refer to the Looping over form fields section in the manual.
before you do this, view the HTML source and confirm that id_currentWeightKg is the correct id for the field in question. If not use replace with the correct one.

How can you manually render a form field with its initial value set?

I'm trying to render a form's fields manually so that my designer colleagues could manipulate the input elements within the HTML instead of struggling in Python source.
ie. Instead of declaring form fields like this...
{{ form.first_name }}
.. I actually do ...
<label for="id_first_name">Your name:</label>
<input type="text" value="{{ form.first_name.somehow_get_initial_value_here }}" name="first_name" id="id_first_name" class="blabla" maxlength="30" >
{% if form.first_name.errors %}<span>*** {{ form.first_name.errors|join:", " }}</span>{% endif %}
Problem is that there seems to be no way to get the initial value of the field in the second method. {{ form.first_name }} statement does render the input element with the proper initial value but somehow there is nothing like {{ form.first_name.initial_value }} field when you want to render the form manually.
There is an interesting long standing ticket about this very issue. There is sample code to implement a template filter in the comments that should do what you need:
http://code.djangoproject.com/ticket/10427
<input value="{{form.name.data|default_if_none:'my_defaut_value'}}" ... />
You will have to use default_if_none because the implicit value of a bound field will not be stored in data. More details here

Categories