Commit 55de42a7 authored by Serge S. Koval's avatar Serge S. Koval

New ajax refs configuration format for mongoengine/peewee backends

parent ce5b36ef
...@@ -5,17 +5,38 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE ...@@ -5,17 +5,38 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
class QueryAjaxModelLoader(AjaxModelLoader): class QueryAjaxModelLoader(AjaxModelLoader):
def __init__(self, name, model, fields): def __init__(self, name, model, **options):
""" """
Constructor. Constructor.
:param fields: :param fields:
Fields to run query against Fields to run query against
""" """
super(QueryAjaxModelLoader, self).__init__(name) super(QueryAjaxModelLoader, self).__init__(name, options)
self.model = model self.model = model
self.fields = fields 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): def format(self, model):
if not model: if not model:
...@@ -31,7 +52,7 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -31,7 +52,7 @@ class QueryAjaxModelLoader(AjaxModelLoader):
criteria = None criteria = None
for field in self.fields: for field in self._cached_fields:
flt = {u'%s__icontains' % field.name: term} flt = {u'%s__icontains' % field.name: term}
if not criteria: if not criteria:
...@@ -47,7 +68,7 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -47,7 +68,7 @@ class QueryAjaxModelLoader(AjaxModelLoader):
return query.limit(limit).all() return query.limit(limit).all()
def create_ajax_loader(model, name, field_name, fields): def create_ajax_loader(model, name, field_name, opts):
prop = getattr(model, field_name, None) prop = getattr(model, field_name, None)
if prop is None: if prop is None:
...@@ -56,20 +77,7 @@ def create_ajax_loader(model, name, field_name, fields): ...@@ -56,20 +77,7 @@ def create_ajax_loader(model, name, field_name, fields):
# TODO: Check for field # TODO: Check for field
remote_model = prop.document_type remote_model = prop.document_type
remote_fields = [] return QueryAjaxModelLoader(name, remote_model, **opts)
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 process_ajax_references(references, view): def process_ajax_references(references, view):
...@@ -95,7 +103,7 @@ def process_ajax_references(references, view): ...@@ -95,7 +103,7 @@ def process_ajax_references(references, view):
for field_name, opts in iteritems(ajax_refs): for field_name, opts in iteritems(ajax_refs):
child_name = make_name(base, field_name) child_name = make_name(base, field_name)
if isinstance(opts, (list, tuple)): if isinstance(opts, dict):
loader = create_ajax_loader(field.document_type_obj, child_name, field_name, opts) loader = create_ajax_loader(field.document_type_obj, child_name, field_name, opts)
else: else:
loader = opts loader = opts
......
...@@ -364,8 +364,8 @@ class ModelView(BaseModelView): ...@@ -364,8 +364,8 @@ class ModelView(BaseModelView):
return form_class return form_class
# AJAX foreignkey support # AJAX foreignkey support
def _create_ajax_loader(self, name, fields): def _create_ajax_loader(self, name, opts):
return create_ajax_loader(self.model, name, name, fields) return create_ajax_loader(self.model, name, name, opts)
def get_query(self): def get_query(self):
""" """
......
...@@ -5,19 +5,41 @@ from .tools import get_primary_key ...@@ -5,19 +5,41 @@ from .tools import get_primary_key
class QueryAjaxModelLoader(AjaxModelLoader): class QueryAjaxModelLoader(AjaxModelLoader):
def __init__(self, name, model, fields): def __init__(self, name, model, **options):
""" """
Constructor. Constructor.
:param fields: :param fields:
Fields to run query against Fields to run query against
""" """
super(QueryAjaxModelLoader, self).__init__(name) super(QueryAjaxModelLoader, self).__init__(name, options)
self.model = model self.model = model
self.fields = fields self.fields = options.get('fields')
if not self.fields:
raise ValueError('AJAX loading requires `fields` to be specified for %s.%s' % (model, self.name))
self._cached_fields = self._process_fields()
self.pk = get_primary_key(model) self.pk = get_primary_key(model)
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): def format(self, model):
if not model: if not model:
return None return None
...@@ -31,7 +53,7 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -31,7 +53,7 @@ class QueryAjaxModelLoader(AjaxModelLoader):
query = self.model.select() query = self.model.select()
stmt = None stmt = None
for field in self.fields: for field in self._cached_fields:
q = field ** (u'%%%s%%' % term) q = field ** (u'%%%s%%' % term)
if stmt is None: if stmt is None:
...@@ -47,7 +69,7 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -47,7 +69,7 @@ class QueryAjaxModelLoader(AjaxModelLoader):
return list(query.limit(limit).execute()) return list(query.limit(limit).execute())
def create_ajax_loader(model, name, field_name, fields): def create_ajax_loader(model, name, field_name, options):
prop = getattr(model, field_name, None) prop = getattr(model, field_name, None)
if prop is None: if prop is None:
...@@ -55,17 +77,4 @@ def create_ajax_loader(model, name, field_name, fields): ...@@ -55,17 +77,4 @@ def create_ajax_loader(model, name, field_name, fields):
# TODO: Check for field # TODO: Check for field
remote_model = prop.rel_model remote_model = prop.rel_model
remote_fields = [] return QueryAjaxModelLoader(name, remote_model, **options)
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)
...@@ -13,7 +13,7 @@ from flask.ext.admin.contrib.peewee import filters ...@@ -13,7 +13,7 @@ from flask.ext.admin.contrib.peewee import filters
from .form import get_form, CustomModelConverter, InlineModelConverter, save_inline from .form import get_form, CustomModelConverter, InlineModelConverter, save_inline
from .tools import get_primary_key, parse_like_term from .tools import get_primary_key, parse_like_term
from .ajax import QueryAjaxModelLoader, create_ajax_loader from .ajax import create_ajax_loader
class ModelView(BaseModelView): class ModelView(BaseModelView):
...@@ -243,8 +243,8 @@ class ModelView(BaseModelView): ...@@ -243,8 +243,8 @@ class ModelView(BaseModelView):
return form_class return form_class
# AJAX foreignkey support # AJAX foreignkey support
def _create_ajax_loader(self, name, fields): def _create_ajax_loader(self, name, options):
return create_ajax_loader(self.model, name, name, fields) return create_ajax_loader(self.model, name, name, options)
def _handle_join(self, query, field, joins): def _handle_join(self, query, field, joins):
if field.model_class != self.model: if field.model_class != self.model:
......
...@@ -5,7 +5,7 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE ...@@ -5,7 +5,7 @@ from flask.ext.admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
class QueryAjaxModelLoader(AjaxModelLoader): class QueryAjaxModelLoader(AjaxModelLoader):
def __init__(self, name, session, model, options): def __init__(self, name, session, model, **options):
""" """
Constructor. Constructor.
...@@ -74,4 +74,4 @@ def create_ajax_loader(model, session, name, field_name, options): ...@@ -74,4 +74,4 @@ def create_ajax_loader(model, session, name, field_name, options):
raise ValueError('%s.%s is not a relation.' % (model, field_name)) raise ValueError('%s.%s is not a relation.' % (model, field_name))
remote_model = attr.prop.mapper.class_ remote_model = attr.prop.mapper.class_
return QueryAjaxModelLoader(name, session, remote_model, options) return QueryAjaxModelLoader(name, session, remote_model, **options)
...@@ -384,7 +384,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -384,7 +384,7 @@ class BaseModelView(BaseView, ActionsMixin):
class MyModelView(BaseModelView): class MyModelView(BaseModelView):
form_ajax_refs = { form_ajax_refs = {
'user': QueryAjaxModelLoader('user', db.session, User, page_size=10) 'user': QueryAjaxModelLoader('user', db.session, User, fields=['email'], page_size=10)
} }
If you need custom loading functionality, you can implement your custom loading behavior If you need custom loading functionality, you can implement your custom loading behavior
......
...@@ -375,7 +375,9 @@ def test_ajax_fk(): ...@@ -375,7 +375,9 @@ def test_ajax_fk():
Model2, Model2,
url='view', url='view',
form_ajax_refs={ form_ajax_refs={
'model1': ('test1', 'test2') 'model1': {
'fields': ('test1', 'test2')
}
} }
) )
admin.add_view(view) admin.add_view(view)
...@@ -448,7 +450,9 @@ def test_nested_ajax_refs(): ...@@ -448,7 +450,9 @@ def test_nested_ajax_refs():
form_subdocuments = { form_subdocuments = {
'nested': { 'nested': {
'form_ajax_refs': { 'form_ajax_refs': {
'comment': ['name'] 'comment': {
'fields': ['name']
}
} }
} }
} }
......
...@@ -220,7 +220,9 @@ def test_ajax_fk(): ...@@ -220,7 +220,9 @@ def test_ajax_fk():
Model2, Model2,
url='view', url='view',
form_ajax_refs={ form_ajax_refs={
'model1': ('test1', 'test2') 'model1': {
'fields': ('test1', 'test2')
}
} }
) )
admin.add_view(view) admin.add_view(view)
......
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