Skip to content

Instantly share code, notes, and snippets.

@pawl
Created December 30, 2014 10:59
Show Gist options
  • Save pawl/06c075653d05cbaafae0 to your computer and use it in GitHub Desktop.
Save pawl/06c075653d05cbaafae0 to your computer and use it in GitHub Desktop.
Flask Inline Editing Example Using WTForms + X-Editable
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>title</title>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet"/>
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/js/bootstrap-editable.min.js"></script>
</head>
<body>
{{ form.test1(pk=5, value="blahtest") }}
{{ form.test2(pk=6, value="blahtest2") }}
<script>
$(document).ready(function() {
$('#test1').editable({
placement: 'bottom',
params: function(params) {
// make x-editable act like a normal form field
var newParams = {};
newParams[params.name + '-' + params.pk] = params.value;
return newParams;
}
});
$('#test2').editable({
placement: 'bottom',
params: function(params) {
// make x-editable's POST act like a normal form field
var newParams = {};
newParams[params.name + '-' + params.pk] = params.value;
return newParams;
}
});
});
</script>
</body>
</html>
import wtforms
from wtforms.widgets import HTMLString, html_params
from flask import Flask, request, render_template
from flask.ext.sqlalchemy import SQLAlchemy
from datetime import date, datetime, time
app = Flask(__name__)
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
db = SQLAlchemy(app)
class Model1(db.Model):
def __init__(self, test1=None, test2=None, test3=None, test4=None,
bool_field=False, date_field=None, time_field=None, datetime_field=None,
int_field=None):
self.test1 = test1
self.test2 = test2
self.test3 = test3
self.test4 = test4
self.bool_field = bool_field
self.date_field = date_field
self.time_field = time_field
self.datetime_field = datetime_field
self.int_field = int_field
id = db.Column(db.Integer, primary_key=True)
test1 = db.Column(db.String(20))
test2 = db.Column(db.Unicode(20))
test3 = db.Column(db.Text)
test4 = db.Column(db.UnicodeText)
bool_field = db.Column(db.Boolean)
enum_field = db.Column(db.Enum('model1_v1', 'model1_v1'), nullable=True)
int_field = db.Column(db.Integer)
date_field = db.Column(db.Date)
time_field = db.Column(db.Time)
datetime_field = db.Column(db.DateTime)
class XEditableWidget(object):
def __call__(self, field, **kwargs):
# get Field from FieldList and create x-editable link based on it
subfield = field.pop_entry()
value = kwargs.pop("value", "")
kwargs.setdefault('data-role', 'x-editable')
kwargs.setdefault('data-url', '/')
kwargs.setdefault('id', field.id)
kwargs.setdefault('name', field.name)
kwargs.setdefault('href', '#')
if not kwargs.get('pk'):
raise Exception('pk required')
kwargs['data-pk'] = kwargs.pop("pk")
if isinstance(subfield, wtforms.StringField):
kwargs['data-type'] = 'text'
elif isinstance(subfield, wtforms.BooleanField):
kwargs['data-type'] = 'select'
elif isinstance(subfield, wtforms.RadioField):
kwargs['data-type'] = 'select'
elif isinstance(subfield, wtforms.SelectField):
kwargs['data-type'] = 'select'
elif isinstance(subfield, wtforms.DateField):
kwargs['data-type'] = 'date'
elif isinstance(subfield, wtforms.DateTimeField):
kwargs['data-type'] = 'datetime'
elif isinstance(subfield, wtforms.IntegerField):
kwargs['data-type'] = 'number'
elif isinstance(subfield, wtforms.TextAreaField):
kwargs['data-type'] = 'textarea'
else:
raise Exception('Unsupported field type: %s' % (type(subfield),))
return HTMLString('<a %s>%s</a>' % (html_params(**kwargs), value))
class XEditableForm(wtforms.Form):
# min_entries=1 is required, because XEditableWidget needs at least 1 entry
test1 = wtforms.FieldList(wtforms.StringField(), widget=XEditableWidget(), min_entries=1)
test2 = wtforms.FieldList(wtforms.StringField(), widget=XEditableWidget(), min_entries=1)
@app.route('/', methods=['POST', 'GET'])
def index():
form = XEditableForm(request.form)
if (request.method == "POST") and form.validate():
for x in form:
# last_index will be set if a field is submitted
if getattr(x, 'last_index', None):
model = Model1.query.get(x.last_index)
setattr(model, x.name, x.data.pop())
db.session.commit()
elif (request.method == "POST") and not form.validate():
print "Errors", form.errors
for x in Model1.query.all():
print x.test1, x.test2
return render_template('example.html', form=form)
def build_sample_db():
db.drop_all()
db.create_all()
model_bool = Model1('model_bool', bool_field=True)
model1_obj2 = Model1('model1_obj2')
model1_obj3 = Model1('model1_obj3', test2=u"blah")
model1_obj4 = Model1('model1_obj4', test3="blah")
model1_obj5 = Model1('model1_obj5', test4=u"blah")
date_obj1 = Model1('date_obj1', date_field=date(2014,11,17))
time_obj1 = Model1('time_obj1', time_field=time(11,10,9))
datetime_obj1 = Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0))
int_obj1 = Model1('int_obj1', int_field=5000)
int_obj2 = Model1('int_obj2', int_field=9000)
db.session.add_all([
model_bool, model1_obj2, model1_obj3, model1_obj4, model1_obj5,
date_obj1, time_obj1, datetime_obj1, int_obj1, int_obj2
])
db.session.commit()
if __name__ == '__main__':
build_sample_db()
app.run(debug=True, host="0.0.0.0", port=5001)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment