How to render my TextArea with WTForms? - python

To render my textareafield with a specified number of columns and rows with WTForms, how do I set the number of columns and rows? I followed the instructions from this question but it didn't work:
How to specify rows and columns of a <textarea > tag using wtforms
I tried adding a widget but it didn't work:
class AForm(Form):
name = TextField('Name', [validators.Length(min=4)])
title = TextField('Title', [validators.Length(min=4)])
text = TextAreaField('Text', widget=TextArea(row=70, cols=11))
phonenumber = TextField('Phone number')
phonenumberhide = BooleanField('Display phone number on site')
price = TextField('Price')
password = PasswordField('Password')
email = TextField('Email', [
validators.Length(min=6, message=_('Little short for an email address?')),
validators.Email(message=_('That\'s not a valid email address.'))
])
TypeError: object.new() takes no parameters

Very old question, but since the WTF-Form documentation isn't clear I'm posting my working example. OP, hope you are not still working on this. :-)
form
from flask_wtf import Form
from wtforms.fields import StringField
from wtforms.widgets import TextArea
class PostForm(Form):
title = StringField(u'title', validators=[DataRequired()])
body = StringField(u'Text', widget=TextArea())
template
{% extends "base.html" %}
{% block title %}Create Post{% endblock %}
{% block content %}
<H3>Create/Edit Post</H3>
<form action="" method=post>
{{form.hidden_tag()}}
<dl>
<dt>Title:
<dd>{{ form.title }}
<dt>Post:
<dd>{{ form.body(cols="35", rows="20") }}}
</dl>
<p>
<input type=submit value="Publish">
</form>
{% endblock %}

There is no need to update the template for this issue. You can set the rows and cols in the definition of TextAreaField. Here is the sample: \
class AForm(Form):
text = TextAreaField('Text', render_kw={"rows": 70, "cols": 11})
For render_kw, if provided, a dictionary which provides default keywords will be given to the widget at render time.

TextArea field can be also implemented without any widgets:
forms.py
from wtforms import Form, TextField, TextAreaField
class ContactForm(Form):
name = TextField('Name')
email = TextField('Email Address')
body = TextAreaField('Message Body')
template.html
...
<form method="POST" action="">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name(size=30) }} <br/>
{{ form.email.label }} {{ form.email(size=30) }} <br/>
{{ form.body.label }} {{ form.body(cols="35", rows="20") }} <br/>
<input type="submit" value="Submit"/>
</form>
...

I want to add here that the solutions above which suggest to use render_kw indeed works UNDER THE CONDITION that height for the text area IS NOT set.
so if you have a field:
temp = TextAreaField('temp', render_kw={'rows':20})
and in your HTML file you write:
{{ form.temp(class_='someclass' )}}
then in the CSS definition of someclass, height should not be set as this will conflict with your rows settings and apparently height has precedence above rows.

Related

How to apply style to a Django form?

It is possible to change the style of form in the view?
I found in documentation this code:
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="id_message">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="id_sender">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="id_cc_myself">CC yourself?</label>
{{ form.cc_myself }}
</div>
<p><input type="submit" value="Send message" /></p>
</form>
But it just put a ugly input. I want to apply a class, or a css in this input. Is it possible?
This is my form:
class LoginView(NextUrlMixin, RequestFormAttachMixin, FormView):
form_class = LoginForm
success_url = '/'
template_name = 'accounts/login.html'
default_next = '/'
class LoginForm(forms.Form):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
If you are use a custom css set the class CSS on the forms example:
email = forms.EmailField(label='Email')
email.widget.attrs.update({'class':'customClass', 'required':'required'})
in this case set a customClass if you are using Bootstrap maybe you can use someone like this:
email = forms.EmailField(label='Email')
email.widget.attrs.update({'class':'form-control', 'required':'required'})
this code is on your forms.pyp .. good luck
don't forget load your css file on your template
You can do so by applying some attributes to the widget that you use:
more info can be found here Official Django Documentation
for instance:
email = forms.EmailField(label='Email',
widget=forms.TextInput(attrs={'class':'class_value','placeholder':"Email here"}))
If you want to have the full control of the form html by keeping the same behavior as the one generated by django, the following will work
<input type="email" name="email" id="id_email" value="{{form.email.value}}" class='class_name' attrs='attrs' >
{{ form.email.errors}} <!-- track errors for this field -->
Yes. You can attach a css file to your form (place a {{ form.media }} in your template) with this:
class LoginForm(forms.Form):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
class Media:
css = {
'all': ('login-form-layout.css',)
}
js = (
'https://some-cdn.com/some-framework.js'
'login-form-script.js',
)
Inputs have an ID like id_fiedname so login-form-layout.css can be something like:
#id_email, #id_password {
width: 200px;
}
You can do a lot with CSS and with javascript there are endless possibilities.
You may want to check "Customizing widget instances" at the official Django documentation. For example, you can attach arbitrary attributes to the input tag using the attrs argument:
email = forms.EmailField(
label='Email',
widget=forms.TextInput(attrs{
'class': 'my-super-special-input',
'placeholder': "mailbox#example.com"
}),
)
There are other possibilities there, so check it out.
Use Django widget_tweaks. It’s real convenient. And you can easily change any attribute you want.
{% load widget_tweaks %}
{% render_field form.field class=“your-class” %}

How to have radio buttons with Materialize and WTForms?

In Materialize you define the radio group of a radio button using the attribute name, but Flask-WTForms binds the input with an attribute name.
If I have the following in my template:
{{ form.radio1(type='radio', name='group1') }}
{{ form.radio2(type='radio', name='group1') }}
There will be an error:
TypeError: html_params() got multiple values for keyword argument 'name'
And if we don't add the name, the radios won't work as radios, just as checkboxes, as expected.
How can i get around this?
This is my form class:
class AbcForm(FlaskForm):
field1 = HiddenField('Field1')
field2 = HiddenField('Field2')
and then at runtime I'll dynamically add the radios, here's a simplification:
class F(AbcForm):
pass
setattr(F, radio1, BooleanField('Radio1')
setattr(F, radio2, BooleanField('Radio2')
form = F(field1=x, field2=y)
You can't set the name attribute in your field, wtforms already does that for you.
Use the RadioField instead of HiddenField:
from wtforms import RadioField
from flask_wtf import Form
class YourForm(Form):
radio_group = RadioField('label', choices=[('value','description'),('value_two','some other description')])
(...)
Then, in your endpoint:
#route('/your/route')
def your_endpoint():
your_form = YourForm()
(...)
return render_template('/your/template.html', form=your_form)
Finally, in your template:
<form action="#">
{% for subfield in form.radio_group %}
<p>
{{ subfield }}
{{ subfield.label }}
</p>
{% endfor %}
</form>
This generates the following code:
<form action="#">
<p>
<input id="radio_group-0" name="radio_group" type="radio" value="value">
<label for="radio_group-0">description</label>
</p>
<p>
<input id="radio_group-1" name="radio_group" type="radio" value="value_two">
<label for="radio_group-1">some other description</label>
</p>
</form>
Which, given materialize is included in the template, will render the radio buttons properly as shown in this plunker.

Django ClearableInputField in form doesn't render in HTML [duplicate]

This question already has an answer here:
Customize the styles of Django ClearableFileInput widget
(1 answer)
Closed 6 years ago.
I'm working on a web app that has photo upload functionality. I created a ModelForm to gather minimal user info plus a photo, and when I render it in HTML as {{ form.as_p }}, the field that allows the user to upload an image shows up just fine. The problem is, the form doesn't look good.
I need to be able to manually render the form in order to make it look better. I have written the HTML for this, and everything looks right except for the ImageFileField. Only the label gets rendered, not the upload button, checkbox to clear the file, etc.
What do I need to do to get the ImageFileField from the ModelForm to render correctly in my custom HTML? I've looked at the Django docs up and down, looked here on SO and can't find anyone else who's had this issue. Many thanks in advance!
forms.py snippet
class PostForm(forms.ModelForm):
class Meta:
model = Items
fields = ('title', 'description', 'image_file')
new_item.html snippet
<form enctype="multipart/form-data" method="post" action="" class="post-form">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.title.errors }}
<label for="{{ form.title.id_for_label }}">Title:</label><br>
{{ form.title }}
</div><br>
<div class="fieldWrapper">
{{ form.description.errors }}
<label for="{{ form.description.id_for_label }}">Description: </label><br>
{{ form.description }}
</div><br>
<div class="fieldWrapper">
{{ form.image_field.errors }}
<label for="{{ form.image_field.id_for_label }}">Image (optional):</label><br>
{{ form.image_field }}
</div>
<button type="submit" class="save btn btn-default">Save</button>
</form>
models.py snippet
class Items(models.Model):
title = models.CharField(max_length=1000, null=False)
description = models.TextField(max_length=1000, null=False)
image_file = models.ImageField(max_length=1000,
blank=True,
default='',
null=True,
upload_to='item_photos')
By default django ModelForm uses django.forms.ImageField and not ClearableInputField for django.db.ImageField as revealed at https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#field-types
And I do believe you actually meant ClearableFileInput
ClearableFileInput¶
class ClearableFileInput File upload input: ,
with an additional checkbox input to clear the field’s value, if the
field is not required and has initial data.
How you can make use of it is by changing the widget in the class meta
class PostForm(forms.ModelForm):
class Meta:
model = Items
fields = ('title', 'description', 'image_file')
widgets = {
'name': ClearableFileInput(),
}
I ended up using the Chrome tool to inspect the HTML source for the page that rendered correctly (but ugly), and used that as a guide to custom build the form in HTML to my liking. This is what I needed to add into my HTML form to get it right:
{% if item.image_file %}
Currently:
{{item.image_file.url}}
<input id="image_file-clear_id" name="image_file-clear" type="checkbox" /> <label for="image_file-clear_id">Clear</label><br />Change: <input id="id_image_file" name="image_file" type="file" /></p>
{% endif %}
{% if not item.image_file %}
<input id="id_image_file" name="image_file" type="file" /></p>
{% endif %}

Dynamically change WTForms field type between SelectField and HiddenField

I have a WTForms field (value_currency) that I want to sometimes be a SelectField and sometimes a HiddenField. I use the same view and template for a page that both creates new items and edits existing items. If I load the page to create a new item, I want this field to be a SelectField, and if I load the page to edit an existing item, I want this field to be a HiddenField because it's a non-editable field.
Here is what I have so far:
FORM
class PromoForm(Form):
value = StringField('value')
currencies = Currency.query.order_by(Currency.id).all()
currency_choices = []
for currency in currencies:
currency_choice = (currency.id, currency.name)
currency_choices.append(currency_choice)
value_currency = SelectField('value_currency', choices=currency_choices)
VIEW
#app.route('/promo/<id>', methods=['GET', 'POST'])
#login_required
def promo(id):
form = PromoForm()
# Existing promo will pass in its id
# id = 0 if a new promo is to be created
if id != str(0):
# Load existing promo
promo = Promo.query.get(id)
# display value in decimal format
form.value.default = "{0}.{1:0>2}".format(
promo.value_cents//100, promo.value_cents%100)
form.process()
return render_template('promo.html', promo=promo, form=form)
else:
# New promo
audit_log('GET', client, session=session)
return render_template('promo.html', form=form)
TEMPLATE
{% extends "base.html" %}
{% block content %}
{% if promo is defined %}
<form action="{{ url_for('.promo', id=promo.id) }}" method="post">
{% else %}
<form action="{{ url_for('.promo', id=0) }}" method="post">
{% endif %}
{{ form.hidden_tag() }}
<div>
<label for="value">Promo Value</label>
{% if promo is defined %}
{{ form.value() }}
{% else %}
{{ form.value() }}
{% endif %}
{% for error in form.value.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
{% if promo is defined %}
# ----> Promo.value_currency should be a hidden field here (Doesn't work)
{{ promo.value_currency }}
{% else %}
# ----> Promo.value_currency is a select field here (Currently works)
{{ form.value_currency() }}
{% endif %}
</div>
<div class="submit_btn">
{% if promo is defined %}
<input type="submit" value="Update Promo">
{% else %}
<input type="submit" value="Create Promo">
{% endif %}
</div>
{% endblock %}
I know I can just simply hardcode the hidden input element and drop in the value with Jinja, but I prefer to do it with WTForms and not do any form element hard coding. Is that possible?
See (duplicated) question: Flask, WTForms: Is there a way to make a StringField in the form _temporarily_ hidden?.
You cannot just omit the field, and you cannot change its object type (from SelectField to HiddenField) either.
However, you can change its widget object dynamically.
Replace this with a HiddenInput.
from wtforms.widgets import HiddenInput
class PromoForm(Form):
value = StringField('value')
currencies = Currency.query.order_by(Currency.id).all()
currency_choices = []
for currency in currencies:
currency_choice = (currency.id, currency.name)
currency_choices.append(currency_choice)
value_currency = SelectField('value_currency', choices=currency_choices)
def hide_value_currency(self, value):
"""
Hide the value_currency field by morping it into a
HiddenInput.
"""
self.value_currency.widget = HiddenInput()
# wtforms chokes if the data attribute is not present
self.value_currency.data = value
# wtforms chokes on SelectField with HiddenInput widget
# if there is no _data() callable
self.value_currency._value = lambda: value
Call form.hide_value_currency(pre_set_value) in your view when required.
No logic in your template necessary.

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 }}

Categories