Is it possible to populate a password field in wtforms in flask?
I've tried this:
capform = RECAPTCHA_Form()
capform.username.data = username
capform.password.data = password
The form is defined like:
class RECAPTCHA_Form(Form):
username = TextField('username', validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
remember_me = BooleanField('Remember me.')
recaptcha = RecaptchaField()
The template looks like this:
<form method="POST" action="">
{{ form.hidden_tag() }}
{{ form.username(size=20) }}
{{ form.password(size=20) }}
{% for error in form.recaptcha.errors %}
<p>{{ error }}</p>
{% endfor %}
{{ form.recaptcha }}
<input type="submit" value="Go">
</form>
I have tried to change the PasswordField to a TextField, and then it works.
Is there some special limitation to populating PasswordFields in wtforms?
Update: After looking through the WTForms docs I found an even better solution. There is a widget arg.
from wtforms import StringField
from wtforms.widgets import PasswordInput
class MyForm(Form):
# ...
password = StringField('Password', widget=PasswordInput(hide_value=False))
As yuji-tomita-tomita pointed out, the PasswordInput class (source) has an hide_value argument, however the constructor of PasswordField (source) does not forward it to the PasswordInput. Here is a PasswordField class that initializes PasswordInput with hide_value=False:
from wtforms import widgets
from wtforms.fields.core import StringField
class PasswordField(StringField):
"""
Original source: https://github.com/wtforms/wtforms/blob/2.0.2/wtforms/fields/simple.py#L35-L42
A StringField, except renders an ``<input type="password">``.
Also, whatever value is accepted by this field is not rendered back
to the browser like normal fields.
"""
widget = widgets.PasswordInput(hide_value=False)
Something I've found with Flask, and Flask apps in general, is that the source is the documentation. Indeed, it looks like by default you cannot populate the field. You can pass an argument hide_value to prevent this behavior.
This is a good call, since if you can populate the field, you have access to the raw password... which could be dangerous.
class PasswordInput(Input):
"""
Render a password input.
For security purposes, this field will not reproduce the value on a form
submit by default. To have the value filled in, set `hide_value` to
`False`.
"""
input_type = 'password'
def __init__(self, hide_value=True):
self.hide_value = hide_value
def __call__(self, field, **kwargs):
if self.hide_value:
kwargs['value'] = ''
return super(
I believe there is an easier way to access the data of the password field, without usinghide_value. In your view, simply add in the request data as an argument to the form's constructor:
from flask import request
capform = RECAPTCHA_Form(request.form)
capform.username.data = username
capform.password.data = password
This should make the password input available for validation, and to be used in testing if desired.
Related
Recently I've decide to create form creation form in Flask web app. After searching form creation found Formfield, FieldList classes in flask wtf forms and I can create the form with these classes. but it doesn't provide that I want to.
First- I am going to create a form creation form which will be help me to create form and fields on management interface.
Second- I want to be able to add the fields, not the same type of field, all different kind, such as (booleanField, StringField, IntegerField, DateTimeField etc.) because, in the form there could be different type of fields for specific reason.
Third- I want to retreive this form whenever I want to use in my view
On the DB models side;
class Form(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.StringField)
fields = db.relationship('FormFields', backref='forms', lazy=True)
class FormFields(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.StringField)
field_type = db.Column(db.StringField)
form_id = db.Column(db.Integer, db.ForeignKey('forms.id'), nullable=False)
And othr tables for StrinField, BooleanField, TextField, etc. etc. should be connected this field model, and when I save the data over this created form, these data should be saved int the correct tables
The reason I am searching this, because I don't want to hardcode the Forms and fields in the code, when I need to new form or field I don't want to update code itself, it should be dynamically updated on the database.
And I want to use sqlalchemy based form creation from management page. And this will help to create anytime new form and relate the fields to the form. And on the internet still I didn't find the these style form creation for Flask, almost all of them creating dynamic for with same type of fields
Any ideas?
Last a couple of weeks I was search how to create dynamically flask form based on models
And #nick-shebanov has been redirect me to another approach EAV impelemntation, which is really diffucult to implement. I've tried :)
And decide to create form based on dictionary, and intend to populate the related attributes from the model and pass it to form as dictionary.
What I've done so far;
# app.py file
from flask_wtf import Form
from flask import Flask, render_template, request, flash
from flask_wtf import FlaskForm
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from wtforms import TextField, IntegerField, HiddenField, StringField, TextAreaField, SubmitField, RadioField,SelectField
from wtforms import validators, ValidationError
app = Flask(__name__)
app.secret_key = 'secret123'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sqlite.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
migrate = Migrate(app, db)
# form class with static fields
class DynamicForm(FlaskForm):
form_type = HiddenField(default='FormType', render_kw={ 'type':'hidden' })
# name = StringField()
#app.route('/', methods=['GET', 'POST'])
def index():
fields = {
'username': 'Username',
'first_name': 'Fisrt Name',
'last_name': 'Last Name',
'email': 'Email',
'mobile_phone': 'Mobile Phone'
}
for key, value in fields.items():
setattr(DynamicForm, key, StringField(value))
form = DynamicForm()
if request.method == 'POST':
# print(dir(request.form))
# print(request.form)
dict = request.form.to_dict()
# print(dict.keys())
print(request.form.to_dict())
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug = True)
# index.html template
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form method="POST">
{{ form.csrf_token }}
{{ form.form_type }}
{% for field in form if field.name != 'csrf_token' %}
{% if field.name != 'form_type' %}
<div>
{{ field.label() }}
{{ field() }}
{% for error in field.errors %}
<div class="error">{{ error }}</div>
{% endfor %}
</div>
{% endif %}
{% endfor %}
<input type="submit" value="Go">
</form>
</body>
</html>
Now I can see my all fields has been rendered including hidden field. When I fill the form and post the data, I can capture it.
But still I didn't achieve to implement save the captured data into database like vertical DB modelling style yet
Here is my simple approach of DB modelling
see image here
Is there suggestions?
I have to make a lot of RadioFields, and I thought it would be good to dynamically generate them, but I can't get the code working. I'm using Flask and flask-wtf.
Form definition:
from flask_wtf import FlaskForm
from wtforms import RadioField, SubmitField
class GenerateForm(FlaskForm):
def binary_generator(self, label_text, yes_text, no_text):
return RadioField(label_text, choices=[(1, yes_text), (0, no_text)])
submit = SubmitField('submit')
Flask app:
import GeneratorForm
form = GeneratorForm
form.radio_one = form.binary_generator('test label', 'yes', 'no')
render_template('file.html', form=form)
Jinja:
{{ form.radio_one.label }}
{{ form.radio_one(style="list-style: none") }}
The Jinja fails with: wtforms.fields.core.UnboundField object has no attribute label
So it looks like the class binary_generator function is working ok, but not constructing the form properly?
Do you need that binary_generator method in GenerateForm ?
Your GenerateForm could look something like this:
from flask_wtf import FlaskForm
from wtforms import RadioField, SubmitField
class GenerateForm(FlaskForm):
radio_fields = RadioField('', choices=[])
submit = SubmitField('submit')
And in your flask application, you need to instantiate your form like this:
import GeneratorForm
form = GeneratorForm() # Instantiate it
form.radio_fields.label = 'Label Example'
form.radio_fields.choices = [('value_1', 'description'), ('value_2', 'description')]
render_template('file.html', form=form)
To render your form in file.html:
<form method="post">
{{ form.hidden_tag() }}
{{ form.radio_fields.label }}
{{ form.radio_fields(style='list-style: none') }}
{{ form.submit }}
</form>
The base class FlaskForm is fairly particular about its construction. To define a dynamic form add the parameters after the base class has instantiated with super(). I.e.
class GenerateForm(FlaskForm):
radio_fields = RadioField('', choices=[])
submit = SubmitField('submit')
def __init__(self, label, choices):
super().__init__()
self.radio_fields.choices = label
self.radio_fields.choices = choices
Then you can instantiate the form with:
GenerateForm('My Label', [('val', 'desc'), ('val2', 'desc2')])]
You can also create a Form Factory in the following way:
def Form(n, *args):
class FormGenerator(FlaskForm):
submit = SubmitField('submit')
for i in range(n):
setattr(FormGenerator, RadioField(args[i][0], choices=args[i][1])
return FormGenerator()
Then you can instantiate the form with:
Form(2, *(('rad1', [('v1', 'd1'), ('v2', 'd2')]), ('rad2', [('v1', 'd1'), ('v2', 'd2')])))
Most of the info I find online is for multiple checkboxes. I just want 1.
I have:
class CategoryForm(FlaskForm):
category = StringField('category',validators=[DataRequired()])
checkbox = BooleanField('Private?')
#app.route('/category/<categoryid>',methods=('GET','POST'))
def category(categoryid):
category = Category.query.get(categoryid)
if request.method == 'POST':
if request.form.get('category'):
category.name = request.form['category']
category.private = request.form['private']
db.session.add(category)
db.session.commit()
return redirect(url_for('index'))
c_form = CategoryForm()
c_form.category.data = category.name
return render_template('category.html',form =c_form,category=category)
And my 'category' template:
<form method="post">
{{ form.hidden_tag() }}
{{ form.checkbox }}
<button type="submit">Go!</button>
</form>
right now my browser renders this:
<peewee.BooleanField object at 0x105122ad0> Go!
Obviously I would like it to render the checkbox instead. How can I do this? Do I need a widget ?
I'm having the impression that you're using the fields from peewee as the fields in your form, that isn't going to work. The most likely case is that you're importing both and one import is overwriting the other.
If you need to have both the model and the form in the same file, use aliases.
from peewee import BooleanField as PeeBool
from wtforms import BooleanField as WTBool
When using the Django built-in Form classes the validation routine does not seem to work.
The form consists simply of firstname and lastname. Firstname is required, and for testing purposes I check if lastname is Smith and raise an exception. When I violate those requirements nothing happens, i.e. no exception is being raised - after submitting the form the defined action (POST to union/VIP_best/) is simply triggered without any validation. The form is called at union/contact/, directed from urls.py to views.ContactView.as_view()
Here is my setup so far:
views.py
from union.forms import ContactForm
class ContactView(generic.edit.FormView):
template_name = 'union/contact.html'
form_class = ContactForm
forms.py
from django import forms
from django.core.exceptions import ValidationError
class ContactForm(forms.Form):
firstname = forms.CharField(label='Vorname', max_length=20, required=True, error_messages={'required': 'Please enter first name!'})
lastname = forms.CharField(label='Nachname', max_length=20)
def clean_lastname(self):
data = self.cleaned_data['lastname']
if data != "Smith":
raise forms.ValidationError("Your last name is not Smith.")
else:
raise forms.ValidationError("Your last name is Smith.")
return data
templates/union/contact.html
<form action="/union/VIP_best/" method="post">
{% csrf_token %}
{{ form.as_table }}
<tr>
<td><input type="submit" value="Submit"></td>
</tr>
</form>
What am i missing so that the .clean() or .is_valid is being triggered?
Do I have to explicitly call Field.clean() and is_valid()? If so, where?
The tutorials and Django documentation do not seem to mention anything the like.
Django 1.7, Python 3.4.2
Your form should be submitting to itself. Meaning, if the form is on /union/contact/, you should be POSTing to /union/contact/. Currently, you have it submitting to a different view/url.
The problem is arising because your form processing is happening in the FormView, not at your success_url(). You need to POST to the view that is actually responsible for the validation of the form (in this case, your ContactView at /union/contact/).
As a side note, it would probably be better to modify the action of the form to use {% url 'your_form_url_name' %}, as opposed to hard-coding the url into the template.
I'm learning Django Framework, and I have a question. To help you understand I will try and explain using the example below:
Suppose that we have some table in db as is:
CREATE TABLE names (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100));
And I have the form in Django Admin as is:
<form>
<textarea name="names"></textarea>
<input type="submit" name="sbt" value="Submit">
</form>
User entered something in the input names in the form and submitted it. Then a script catches this data and splits it into an array (str.split("\n")) and in cycle adding to table names!
And I many quetion:
How i can add form to Django Admin?
How i can catch form data and add this data to somethink table in database?
Thanks.
First of all you must create a django model.
Put this code in models.py.
class Names(models.Model):
name = models.CharField(max_length = 100)
Then you must create the admin model.
Put this code in admin.py.
class NamesAdmin(admin.ModelAdmin):
list_display = ['name']
# whatever you want in your admin panel like filter, search and ...
admin.site.register(Names, NamesAdmin)
I think it meet your request. And for split the names you can override save model method and split the names in there. But if you want to have an extra form, you can easily create a django model form.
Put the code somewhere like admin.py, views.py or forms.py
class NamesForm(forms.ModelForm)
class Meta:
model = Names
That's your model and form. So, if your want to add the form to django admin panel you must create a view for it in django admin. For do this create a view as common.
Put the code in your admin.py or views.py.
def spliter(req):
if req.method == 'POST':
form = NamesForm(req.POST)
if form.is_valid():
for name in form.cleaned_data['names'].split(' '):
Names(name = name).save()
return HttpResponseRedirect('') # wherever you want to redirect
return render(req, 'names.html', {'form': form})
return render(req, 'names.html', {'form': NamesForm()})
Be aware you must create the names.html and put the below code in you html page.
{% extends 'admin/base_site.html' %}
{% block content %}
<!-- /admin/names/spliter/ is your url in admin panel (you can change it whatever you want) -->
<form action="/admin/names/spliter/" method="post" >{% csrf_token %}
{{ form }}
<input type="submit" value="'Send'" >
</form>
{% endblock %}
This is your view and your can use it everywhere. But if you want only the admin have permission to see this page you must add this method too your NamesAdmin class.
def get_urls(self):
return patterns(
'',
(r'^spliter/$', self.admin_site.admin_view(spliter)) # spliter is your view
) + super(NamesAdmin, self).get_urls()
That's It. I hope this can help you.