123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- import mongoengine
- from flask_admin._compat import string_types, as_unicode, iteritems
- from flask_admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
- class QueryAjaxModelLoader(AjaxModelLoader):
- def __init__(self, name, model, **options):
- """
- Constructor.
- :param fields:
- Fields to run query against
- """
- super(QueryAjaxModelLoader, self).__init__(name, options)
- self.model = model
- self.fields = options.get('fields')
- self._cached_fields = self._process_fields()
- if not self.fields:
- raise ValueError('AJAX loading requires `fields` to be specified for %s.%s' % (model, self.name))
- def _process_fields(self):
- remote_fields = []
- for field in self.fields:
- if isinstance(field, string_types):
- attr = getattr(self.model, field, None)
- if not attr:
- raise ValueError('%s.%s does not exist.' % (self.model, field))
- remote_fields.append(attr)
- else:
- remote_fields.append(field)
- return remote_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._cached_fields:
- flt = {u'%s__icontains' % field.name: term}
- if not criteria:
- criteria = mongoengine.Q(**flt)
- else:
- criteria |= mongoengine.Q(**flt)
- query = query.filter(criteria)
- if offset:
- query = query.skip(offset)
- return query.limit(limit).all()
- def create_ajax_loader(model, name, field_name, opts):
- prop = getattr(model, field_name, None)
- if prop is None:
- raise ValueError('Model %s does not have field %s.' % (model, field_name))
- ftype = type(prop).__name__
- if ftype == 'ListField' or ftype == 'SortedListField':
- prop = prop.field
- ftype = type(prop).__name__
- if ftype != 'ReferenceField':
- raise ValueError('Dont know how to convert %s type for AJAX loader' % ftype)
- remote_model = prop.document_type
- return QueryAjaxModelLoader(name, remote_model, **opts)
- def process_ajax_references(references, view):
- def make_name(base, name):
- if base:
- return ('%s-%s' % (base, name)).lower()
- else:
- return as_unicode(name).lower()
- def handle_field(field, subdoc, base):
- ftype = type(field).__name__
- if ftype == 'ListField' or ftype == 'SortedListField':
- child_doc = getattr(subdoc, '_form_subdocuments', {}).get(None)
- if child_doc:
- handle_field(field.field, child_doc, base)
- elif ftype == 'EmbeddedDocumentField':
- result = {}
- ajax_refs = getattr(subdoc, 'form_ajax_refs', {})
- for field_name, opts in iteritems(ajax_refs):
- child_name = make_name(base, field_name)
- if isinstance(opts, dict):
- loader = create_ajax_loader(field.document_type_obj, child_name, field_name, opts)
- else:
- loader = opts
- result[field_name] = loader
- references[child_name] = loader
- subdoc._form_ajax_refs = result
- child_doc = getattr(subdoc, '_form_subdocuments', None)
- if child_doc:
- handle_subdoc(field.document_type_obj, subdoc, base)
- else:
- raise ValueError('Failed to process subdocument field %s' % (field,))
- def handle_subdoc(model, subdoc, base):
- documents = getattr(subdoc, '_form_subdocuments', {})
- for name, doc in iteritems(documents):
- field = getattr(model, name, None)
- if not field:
- raise ValueError('Invalid subdocument field %s.%s' % (model, name))
- handle_field(field, doc, make_name(base, name))
- handle_subdoc(view.model, view, '')
- return references
|