Commit efcc49ed authored by Serge S. Koval's avatar Serge S. Koval

Widget fixes, MongoEngine backend support

parent 8151015e
......@@ -39,4 +39,9 @@ class QueryAjaxModelLoader(AjaxModelLoader):
else:
criteria |= mongoengine.Q(**flt)
return query.filter(criteria).skip(offset).limit(limit)
query = query.filter(criteria)
if offset:
query = query.skip(offset)
return query.limit(limit).all()
......@@ -122,6 +122,8 @@ class AjaxSelectField(SelectFieldBase):
"""
widget = AjaxSelect2Widget()
separator = ','
def __init__(self, loader, label=None, validators=None, allow_blank=False, blank_text=u'', **kwargs):
super(AjaxSelectField, self).__init__(label, validators, **kwargs)
self.loader = loader
......@@ -170,6 +172,7 @@ class AjaxSelectMultipleField(AjaxSelectField):
def __init__(self, loader, label=None, validators=None, default=None, **kwargs):
if default is None:
default = []
super(AjaxSelectMultipleField, self).__init__(loader, label, validators, default=default, **kwargs)
self._invalid_formdata = False
......@@ -198,12 +201,12 @@ class AjaxSelectMultipleField(AjaxSelectField):
data = property(_get_data, _set_data)
def process_formdata(self, valuelist):
self._formdata = set(valuelist)
self._formdata = set()
for field in valuelist:
for n in field.split(self.separator):
self._formdata.add(n)
def pre_validate(self, form):
if self._invalid_formdata:
raise ValidationError(self.gettext(u'Not a valid choice'))
elif self.data:
for item in self.data:
if not self.loader.get_one(item):
raise ValidationError(self.gettext(u'Not a valid choice'))
from flask import url_for, json
from wtforms.widgets import HTMLString, html_params
from flask.ext.admin._compat import as_unicode
from flask.ext.admin.form import RenderTemplateWidget
......@@ -31,13 +32,23 @@ class AjaxSelect2Widget(object):
if self.multiple:
result = []
ids = []
for value in field.data:
result.append(field.loader.format(value))
data = field.loader.format(value)
result.append(data)
ids.append(as_unicode(data[0]))
kwargs['value'] = json.dumps(result)
separator = getattr(field, 'separator', ',')
kwargs['value'] = separator.join(ids)
kwargs['data-json'] = json.dumps(result)
kwargs['data-multiple'] = u'1'
else:
kwargs['value'] = json.dumps(field.loader.format(field.data))
data = field.loader.format(field.data)
if data:
kwargs['value'] = data[0]
kwargs['data-json'] = json.dumps(data)
return HTMLString('<input %s>' % html_params(name=field.name, **kwargs))
......@@ -37,7 +37,8 @@
}
},
initSelection: function(element, callback) {
var value = jQuery.parseJSON(element.val());
$el = $(element);
var value = jQuery.parseJSON($el.attr('data-json'));
var result = null;
if (value) {
......
......@@ -2,7 +2,7 @@ from nose.tools import eq_, ok_
from nose.plugins.skip import SkipTest
# Skip test on PY3
from flask.ext.admin._compat import PY2
from flask.ext.admin._compat import PY2, as_unicode
if not PY2:
raise SkipTest('MongoEngine is not Python 3 compatible')
......@@ -350,3 +350,78 @@ def test_nested_list_subdocument():
ok_('name' in dir(inline_form))
ok_('value' not in dir(inline_form))
def test_ajax_fk():
app, db, admin = setup()
class Model1(db.Document):
test1 = db.StringField(max_length=20)
test2 = db.StringField(max_length=20)
def __str__(self):
return self.test1
class Model2(db.Document):
int_field = db.IntField()
bool_field = db.BooleanField()
model1 = db.ReferenceField(Model1)
Model1.objects.delete()
Model2.objects.delete()
view = CustomModelView(
Model2,
url='view',
form_ajax_refs={
'model1': ('test1', 'test2')
}
)
admin.add_view(view)
ok_(u'model1' in view._form_ajax_refs)
model = Model1(test1=u'first')
model.save()
model2 = Model1(test1=u'foo', test2=u'bar').save()
# Check loader
loader = view._form_ajax_refs[u'model1']
mdl = loader.get_one(model.id)
eq_(mdl.test1, model.test1)
items = loader.get_list(u'fir')
eq_(len(items), 1)
eq_(items[0].id, model.id)
items = loader.get_list(u'bar')
eq_(len(items), 1)
eq_(items[0].test1, u'foo')
# Check form generation
form = view.create_form()
eq_(form.model1.__class__.__name__, u'AjaxSelectField')
with app.test_request_context('/admin/view/'):
ok_(u'value=""' not in form.model1())
form.model1.data = model
needle = u'data-json="[&quot;%s&quot;, &quot;first&quot;]"' % as_unicode(model.id)
ok_(needle in form.model1())
ok_(u'value="%s"' % as_unicode(model.id) in form.model1())
# Check querying
client = app.test_client()
req = client.get(u'/admin/view/ajax/lookup/?name=model1&query=foo')
eq_(req.data, u'[["%s", "foo"]]' % model2.id)
# Check submitting
client.post('/admin/view/new/', data={u'model1': as_unicode(model.id)})
mdl = Model2.objects.first()
ok_(mdl is not None)
ok_(mdl.model1 is not None)
eq_(mdl.model1.id, model.id)
eq_(mdl.model1.test1, u'first')
......@@ -698,7 +698,8 @@ def test_ajax_fk():
ok_(u'model1' in view._form_ajax_refs)
model = Model1(u'first')
db.session.add_all([model, Model1(u'foo', u'bar')])
model2 = Model1(u'foo', u'bar')
db.session.add_all([model, model2])
db.session.commit()
# Check loader
......@@ -719,16 +720,17 @@ def test_ajax_fk():
eq_(form.model1.__class__.__name__, u'AjaxSelectField')
with app.test_request_context('/admin/view/'):
ok_(u'value="null"' in form.model1())
ok_(u'value=""' not in form.model1())
form.model1.data = model
ok_(u'value="[1, &quot;first&quot;]"' in form.model1())
ok_(u'data-json="[%s, &quot;first&quot;]"' % model.id in form.model1())
ok_(u'value="1"' in form.model1())
# Check querying
client = app.test_client()
req = client.get(u'/admin/view/ajax/lookup/?name=model1&query=foo')
eq_(req.data, u'[[2, "foo"]]')
eq_(req.data, u'[[%s, "foo"]]' % model2.id)
# Check submitting
req = client.post('/admin/view/new/', data={u'model1': as_unicode(model.id)})
......@@ -738,3 +740,67 @@ def test_ajax_fk():
ok_(mdl.model1 is not None)
eq_(mdl.model1.id, model.id)
eq_(mdl.model1.test1, u'first')
def test_ajax_fk_multi():
app, db, admin = setup()
class Model1(db.Model):
__tablename__ = 'model1'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
def __str__(self):
return self.name
table = db.Table('m2m', db.Model.metadata,
db.Column('model1_id', db.Integer, db.ForeignKey('model1.id')),
db.Column('model2_id', db.Integer, db.ForeignKey('model2.id'))
)
class Model2(db.Model):
__tablename__ = 'model2'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
model1_id = db.Column(db.Integer(), db.ForeignKey(Model1.id))
model1 = db.relationship(Model1, backref='models2', secondary=table)
db.create_all()
view = CustomModelView(
Model2, db.session,
url='view',
form_ajax_refs={
'model1': ('name',)
}
)
admin.add_view(view)
ok_(u'model1' in view._form_ajax_refs)
model = Model1(name=u'first')
db.session.add_all([model, Model1(name=u'foo')])
db.session.commit()
# Check form generation
form = view.create_form()
eq_(form.model1.__class__.__name__, u'AjaxSelectMultipleField')
with app.test_request_context('/admin/view/'):
print form.model1()
ok_(u'data-json="[]"' in form.model1())
form.model1.data = [model]
ok_(u'data-json="[[1, &quot;first&quot;]]"' in form.model1())
# Check submitting
client = app.test_client()
client.post('/admin/view/new/', data={u'model1': as_unicode(model.id)})
mdl = db.session.query(Model2).first()
ok_(mdl is not None)
ok_(mdl.model1 is not None)
eq_(len(mdl.model1), 1)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment