Commit 7a4d2b7b authored by Serge S. Koval's avatar Serge S. Koval

Added MongoEngine subdocument pre-caching

parent 5202791f
import mongoengine import mongoengine
from flask.ext.admin._compat import as_unicode from flask.ext.admin._compat import string_types, as_unicode
from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
...@@ -45,3 +45,28 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -45,3 +45,28 @@ class QueryAjaxModelLoader(AjaxModelLoader):
query = query.skip(offset) query = query.skip(offset)
return query.limit(limit).all() return query.limit(limit).all()
def create_ajax_loader(model, name, fields):
prop = getattr(model, name, None)
if prop is None:
raise ValueError('Model %s does not have field %s.' % (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)
...@@ -5,16 +5,13 @@ from wtforms import fields, validators ...@@ -5,16 +5,13 @@ from wtforms import fields, validators
from flask.ext.mongoengine.wtf import orm, fields as mongo_fields 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
from flask.ext.admin.model.fields import InlineFieldList, AjaxSelectField, AjaxSelectMultipleField from flask.ext.admin.model.fields import InlineFieldList, AjaxSelectField
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
from .fields import ModelFormField, MongoFileField, MongoImageField from .fields import ModelFormField, MongoFileField, MongoImageField
from .subdoc import EmbeddedForm
class EmbeddedForm(InlineBaseFormAdmin):
pass
class CustomModelConverter(orm.ModelConverter): class CustomModelConverter(orm.ModelConverter):
...@@ -39,19 +36,14 @@ class CustomModelConverter(orm.ModelConverter): ...@@ -39,19 +36,14 @@ class CustomModelConverter(orm.ModelConverter):
return None return None
def _get_subdocument_config(self, name): def _get_subdocument_config(self, name):
config = getattr(self.view, 'form_subdocuments', {}) config = getattr(self.view, '_form_subdocuments', {})
p = config.get(name) p = config.get(name)
if not p: if not p:
return EmbeddedForm() return EmbeddedForm()
if isinstance(p, dict):
return EmbeddedForm(**p)
elif isinstance(p, EmbeddedForm):
return p return p
raise ValueError('Invalid subdocument type: expecting dict or instance of flask.ext.admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p))
def clone_converter(self, view): def clone_converter(self, view):
return self.__class__(view) return self.__class__(view)
......
...@@ -18,7 +18,8 @@ from .form import get_form, CustomModelConverter ...@@ -18,7 +18,8 @@ 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 from .ajax import QueryAjaxModelLoader, create_ajax_loader
from .subdoc import convert_subdocuments
SORTABLE_FIELDS = set(( SORTABLE_FIELDS = set((
...@@ -98,7 +99,7 @@ class ModelView(BaseModelView): ...@@ -98,7 +99,7 @@ class ModelView(BaseModelView):
List of allowed search field types. List of allowed search field types.
""" """
form_subdocuments = {} form_subdocuments = None
""" """
Subdocument configuration options. Subdocument configuration options.
...@@ -199,6 +200,16 @@ class ModelView(BaseModelView): ...@@ -199,6 +200,16 @@ class ModelView(BaseModelView):
self._primary_key = self.scaffold_pk() self._primary_key = self.scaffold_pk()
def _refresh_cache(self):
# Process subdocuments
if self.form_subdocuments is None:
self.form_subdocuments = {}
self._form_subdocuments = convert_subdocuments(self.form_subdocuments)
# Cache other properties
super(ModelView, self)._refresh_cache()
def _get_model_fields(self, model=None): def _get_model_fields(self, model=None):
""" """
Inspect model and return list of model fields Inspect model and return list of model fields
...@@ -339,28 +350,7 @@ class ModelView(BaseModelView): ...@@ -339,28 +350,7 @@ class ModelView(BaseModelView):
# AJAX foreignkey support # AJAX foreignkey support
def _create_ajax_loader(self, name, fields): def _create_ajax_loader(self, name, fields):
prop = getattr(self.model, name, None) return create_ajax_loader(self.model, name, fields)
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):
""" """
......
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