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.
Related
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
I have been trying to figure out why my Flask form will not properly validate my select field choices even though the choices are coming from the select field options.
My assumption is that the select option when passed back from the server is unicode and is being compared to the choice which is a string, however, I thought coerce=str would fix that. I printed out the form data and request data which is the output below. Why isn't it working?
My code is attached below, removed csrf token key from the output dict. It seems like a very simple thing, but I can't figure it out.
forms.py
class PlatformForm(FlaskForm):
platform_options = [('test', 'Test'), ('test2','Test2')]
platforms = wtforms.SelectField('Platforms', choices=platform_options, coerce=str, validators=[DataRequired()])
views.py
#app.route('/', methods=['POST', 'GET'])
def index():
form = forms.PlatformForm()
if form.is_submitted():
print form.data
print request.form
if form.errors:
print form.errors
return render_template('home.html', form=form)
index.html
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.csrf_token }}
<select class="custom-select" name="platform">
{% for value, text in form.platforms.choices %}<br>
<option value="{{ value }}">{{ text }}</option>
{% endfor %}
</select>
<button id="submit_inputs" type="submit" class="btn btn-default">Submit</button>
</form>
{% endblock %}
output
{'platforms': 'None'}
ImmutableMultiDict([('platform', u'test')])
{'platforms': [u'Not a valid choice']}
EDIT:
I figured out the problem. It's the way I'm creating the Select drop down through HTML and Jinja. Iterating through the choices and creating option tags doesn't seem to instantiate anything in the form data itself when passed back into Python. Changing that whole for loop to just
{{form.platforms}}
created a select drop down field that actually works.
You have a name mismatch. In the form, you named your select field platforms (plural). In the HTML, you use platform (singular).
I recommend that instead of manually rendering the fields in your template, you let WTForms generate the HTML for you. For the form label, you can use {{ form.platforms.label }}, and for the actual field {{ form.platforms() }}. You can pass any attributes you want to field to have as keyword arguments.
I think something might be going wrong because of the way you are rendering the form in your html file. If my hunch is right, try this:
{% extends "base.html" %}
{% block content %}
<h4>Select a Platform</h4>
<form method="POST">
{{ form.hidden_tag() }}
Select: {{ form.plaforms}}
{{ form.submit(class="btn btn-default") }}
</form>
{% endblock %}
and then try if form.validate_on_submit() in your views.py file
taken from this stack overflow answer by pjcunningham:
"validate_on_submit() is a shortcut for is_submitted() and validate().
From the source code, line 89, is_submitted() returns True if the form
submitted is an active request and the method is POST, PUT, PATCH, or
DELETE.
Generally speaking, it is used when a route can accept both GET and
POST methods and you want to validate only on a POST request."
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 }}
In register.html template if I put
{{ form.as_p }}
to use native register form it works. But it is very ugly. So I use it as
{{ form.username}}
{{ form.password1}}
But sometimes when an error occurs, I need to check if register form has any errors [example names]
{% if form.any_error %}
And show the message styled
{{ form.errormessage}} or {{ form.errorlist.values}}
How to achive this in Django with native form and what are the native form variables let us to do this?
I would suggest to take a look at Widget Tweaks
You can add classes and attributes to your Form fields which gives you a lot of control over the Form styling.
<form method='POST' action='' enctype='multipart/form-data'>
{% load widget_tweaks %}
{% csrf_token %}
<span>1. Title: {{ form.title|add_class:"titleCSS" }}</span>
{% if form.errors %}
<span> {{ form.errors|add_class:"errorCSS" }} </span>
{% endif %}
</form>
Or As mentioned before you can use Crispy Forms they work fine and a lot of sites are using it but you have to work into the Crispy Forms package.
With Widget Tweaks you can simply add CSS as you would do it in HTML.
If you are interested in rendering Django forms in elegant and DRY way, you can check Django Crispy forms third party app. It is designed to render forms easily using components from many different popular frontend frameworks (Bootstrap, Uni-form, Foundation).
It uses the correct widgets for all your form field types, and also manages validation errors, displaying errors with the correct markup and style.
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 }}