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): ...@@ -79,6 +79,10 @@ class UserView(ModelView):
class TodoView(ModelView): class TodoView(ModelView):
column_filters = ['done'] column_filters = ['done']
form_ajax_refs = {
'user': ('name',)
}
# Flask views # Flask views
@app.route('/') @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 import ReferenceField
from mongoengine.base import BaseDocument, DocumentMetaclass from mongoengine.base import BaseDocument, DocumentMetaclass
...@@ -8,7 +6,7 @@ from flask.ext.mongoengine.wtf import orm, fields as mongo_fields ...@@ -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 import form
from flask.ext.admin.model.form import FieldPlaceholder, InlineBaseFormAdmin 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.model.widgets import InlineFormWidget
from flask.ext.admin._compat import iteritems from flask.ext.admin._compat import iteritems
...@@ -158,9 +156,14 @@ class CustomModelConverter(orm.ModelConverter): ...@@ -158,9 +156,14 @@ class CustomModelConverter(orm.ModelConverter):
@orm.converts('ReferenceField') @orm.converts('ReferenceField')
def conv_Reference(self, model, field, kwargs): def conv_Reference(self, model, field, kwargs):
kwargs['widget'] = form.Select2Widget()
kwargs['allow_blank'] = not field.required 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) return orm.ModelConverter.conv_Reference(self, model, field, kwargs)
@orm.converts('FileField') @orm.converts('FileField')
......
...@@ -18,6 +18,7 @@ from .form import get_form, CustomModelConverter ...@@ -18,6 +18,7 @@ from .form import get_form, CustomModelConverter
from .typefmt import DEFAULT_FORMATTERS from .typefmt import DEFAULT_FORMATTERS
from .tools import parse_like_term from .tools import parse_like_term
from .helpers import format_error from .helpers import format_error
from .ajax import QueryAjaxModelLoader
SORTABLE_FIELDS = set(( SORTABLE_FIELDS = set((
...@@ -336,6 +337,31 @@ class ModelView(BaseModelView): ...@@ -336,6 +337,31 @@ class ModelView(BaseModelView):
return form_class 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): def get_query(self):
""" """
Returns the QuerySet for this view. By default, it returns all the 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