Commit 8151015e authored by Serge S. Koval's avatar Serge S. Koval

MongoEngine AJAX FK loading

parent 0d73f9a2
......@@ -79,6 +79,10 @@ class UserView(ModelView):
class TodoView(ModelView):
column_filters = ['done']
form_ajax_refs = {
'user': ('name',)
}
# Flask views
@app.route('/')
......
import mongoengine
from flask.ext.admin._compat import as_unicode
from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
class QueryAjaxModelLoader(AjaxModelLoader):
def __init__(self, name, model, fields):
"""
Constructor.
:param fields:
Fields to run query against
"""
super(QueryAjaxModelLoader, self).__init__(name)
self.model = model
self.fields = fields
def format(self, model):
if not model:
return None
return (as_unicode(model.id), as_unicode(model))
def get_one(self, pk):
return self.model.objects.filter(id=pk).first()
def get_list(self, term, offset=0, limit=DEFAULT_PAGE_SIZE):
query = self.model.objects
criteria = None
for field in self.fields:
flt = {'%s__icontains' % field.name: term}
if not criteria:
criteria = mongoengine.Q(**flt)
else:
criteria |= mongoengine.Q(**flt)
return query.filter(criteria).skip(offset).limit(limit)
from operator import attrgetter
from mongoengine import ReferenceField
from mongoengine.base import BaseDocument, DocumentMetaclass
......@@ -8,7 +6,7 @@ from flask.ext.mongoengine.wtf import orm, fields as mongo_fields
from flask.ext.admin import form
from flask.ext.admin.model.form import FieldPlaceholder, InlineBaseFormAdmin
from flask.ext.admin.model.fields import InlineFieldList
from flask.ext.admin.model.fields import InlineFieldList, AjaxSelectField, AjaxSelectMultipleField
from flask.ext.admin.model.widgets import InlineFormWidget
from flask.ext.admin._compat import iteritems
......@@ -158,9 +156,14 @@ class CustomModelConverter(orm.ModelConverter):
@orm.converts('ReferenceField')
def conv_Reference(self, model, field, kwargs):
kwargs['widget'] = form.Select2Widget()
kwargs['allow_blank'] = not field.required
loader = self.view._form_ajax_refs.get(field.name)
if loader:
return AjaxSelectField(loader, **kwargs)
kwargs['widget'] = form.Select2Widget()
return orm.ModelConverter.conv_Reference(self, model, field, kwargs)
@orm.converts('FileField')
......
......@@ -18,6 +18,7 @@ from .form import get_form, CustomModelConverter
from .typefmt import DEFAULT_FORMATTERS
from .tools import parse_like_term
from .helpers import format_error
from .ajax import QueryAjaxModelLoader
SORTABLE_FIELDS = set((
......@@ -336,6 +337,31 @@ class ModelView(BaseModelView):
return form_class
# AJAX foreignkey support
def _create_ajax_loader(self, name, fields):
prop = getattr(self.model, name, None)
if prop is None:
raise ValueError('Model %s does not have field %s.' % (self.model, name))
# TODO: Check for field
remote_model = prop.document_type
remote_fields = []
for field in fields:
if isinstance(field, string_types):
attr = getattr(remote_model, field, None)
if not attr:
raise ValueError('%s.%s does not exist.' % (remote_model, field))
remote_fields.append(attr)
else:
remote_fields.append(field)
return QueryAjaxModelLoader(name, remote_model, remote_fields)
def get_query(self):
"""
Returns the QuerySet for this view. By default, it returns all the
......
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