Created
December 30, 2014 10:59
-
-
Save pawl/06c075653d05cbaafae0 to your computer and use it in GitHub Desktop.
Flask Inline Editing Example Using WTForms + X-Editable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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