Commit e9ef3bf6 authored by P.J. Janse van Rensburg's avatar P.J. Janse van Rensburg

Merge branch 'minor-fixes'

parents 5c3ba0e2 c58bc0da
...@@ -7,6 +7,7 @@ Next release ...@@ -7,6 +7,7 @@ Next release
* Fix display of inline x-editable boolean fields on list view * Fix display of inline x-editable boolean fields on list view
* Add support for several SQLAlchemy-Utils data types * Add support for several SQLAlchemy-Utils data types
* Support searching on SQLAlchemy hybrid properties * Support searching on SQLAlchemy hybrid properties
* Extra URL paramaters are now propagated to the next page when searching / filtering
* Add enum34 dependency when running on legacy Python version * Add enum34 dependency when running on legacy Python version
* Update Mapbox API v1 URL format * Update Mapbox API v1 URL format
* Update jQuery and moment dependencies in templates * Update jQuery and moment dependencies in templates
......
...@@ -58,13 +58,16 @@ class QueryAjaxModelLoader(AjaxModelLoader): ...@@ -58,13 +58,16 @@ class QueryAjaxModelLoader(AjaxModelLoader):
return getattr(model, self.pk), as_unicode(model) return getattr(model, self.pk), as_unicode(model)
def get_query(self):
return self.session.query(self.model)
def get_one(self, pk): def get_one(self, pk):
# prevent autoflush from occuring during populate_obj # prevent autoflush from occuring during populate_obj
with self.session.no_autoflush: with self.session.no_autoflush:
return self.session.query(self.model).get(pk) return self.get_query().get(pk)
def get_list(self, term, offset=0, limit=DEFAULT_PAGE_SIZE): def get_list(self, term, offset=0, limit=DEFAULT_PAGE_SIZE):
query = self.session.query(self.model) query = self.get_query()
filters = (cast(field, String).ilike(u'%%%s%%' % term) for field in self._cached_fields) filters = (cast(field, String).ilike(u'%%%s%%' % term) for field in self._cached_fields)
query = query.filter(or_(*filters)) query = query.filter(or_(*filters))
......
...@@ -1701,29 +1701,39 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -1701,29 +1701,39 @@ class BaseModelView(BaseView, ActionsMixin):
def get_empty_list_message(self): def get_empty_list_message(self):
return gettext('There are no items in the table.') return gettext('There are no items in the table.')
def get_invalid_value_msg(self, value, filter):
"""
Returns message, which should be printed in case of failed validation.
:param value: Invalid value
:param filter: Filter
:return: string
"""
return gettext('Invalid Filter Value: %(value)s', value=value)
# URL generation helpers # URL generation helpers
def _get_list_filter_args(self): def _get_list_filter_args(self):
if self._filters: if self._filters:
filters = [] filters = []
for n in request.args: for arg in request.args:
if not n.startswith('flt'): if not arg.startswith('flt'):
continue continue
if '_' not in n: if '_' not in arg:
continue continue
pos, key = n[3:].split('_', 1) pos, key = arg[3:].split('_', 1)
if key in self._filter_args: if key in self._filter_args:
idx, flt = self._filter_args[key] idx, flt = self._filter_args[key]
value = request.args[n] value = request.args[arg]
if flt.validate(value): if flt.validate(value):
filters.append((pos, (idx, as_unicode(flt.name), value))) data = (pos, (idx, as_unicode(flt.name), value))
filters.append(data)
else: else:
flash(gettext('Invalid Filter Value: %(value)s', value=value), 'error') flash(self.get_invalid_value_msg(value, flt), 'error')
# Sort filters # Sort filters
return [v[1] for v in sorted(filters, key=lambda n: n[0])] return [v[1] for v in sorted(filters, key=lambda n: n[0])]
...@@ -2054,6 +2064,9 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2054,6 +2064,9 @@ class BaseModelView(BaseView, ActionsMixin):
get_pk_value=self.get_pk_value, get_pk_value=self.get_pk_value,
get_value=self.get_list_value, get_value=self.get_list_value,
return_url=self._get_list_url(view_args), return_url=self._get_list_url(view_args),
# Extras
extra_args=view_args.extra_args,
) )
@expose('/new/', methods=('GET', 'POST')) @expose('/new/', methods=('GET', 'POST'))
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
{% macro filter_form() %} {% macro filter_form() %}
<form id="filter_form" method="GET" action="{{ return_url }}"> <form id="filter_form" method="GET" action="{{ return_url }}">
{% for arg_name, arg_value in extra_args.items() %}
<input type="hidden" name="{{ arg_name }}" value="{{ arg_value }}">
{% endfor %}
{% if sort_column is not none %} {% if sort_column is not none %}
<input type="hidden" name="sort" value="{{ sort_column }}"> <input type="hidden" name="sort" value="{{ sort_column }}">
{% endif %} {% endif %}
...@@ -63,6 +66,9 @@ ...@@ -63,6 +66,9 @@
{% for flt_name, flt_value in filter_args.items() %} {% for flt_name, flt_value in filter_args.items() %}
<input type="hidden" name="{{ flt_name }}" value="{{ flt_value }}"> <input type="hidden" name="{{ flt_name }}" value="{{ flt_value }}">
{% endfor %} {% endfor %}
{% for arg_name, arg_value in extra_args.items() %}
<input type="hidden" name="{{ arg_name }}" value="{{ arg_value }}">
{% endfor %}
{% if page_size != default_page_size %} {% if page_size != default_page_size %}
<input type="hidden" name="page_size" value="{{ page_size }}"> <input type="hidden" name="page_size" value="{{ page_size }}">
{% endif %} {% endif %}
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
{% macro filter_form() %} {% macro filter_form() %}
<form id="filter_form" method="GET" action="{{ return_url }}"> <form id="filter_form" method="GET" action="{{ return_url }}">
{% for arg_name, arg_value in extra_args.items() %}
<input type="hidden" name="{{ arg_name }}" value="{{ arg_value }}">
{% endfor %}
{% if sort_column is not none %} {% if sort_column is not none %}
<input type="hidden" name="sort" value="{{ sort_column }}"> <input type="hidden" name="sort" value="{{ sort_column }}">
{% endif %} {% endif %}
...@@ -63,6 +66,9 @@ ...@@ -63,6 +66,9 @@
{% for flt_name, flt_value in filter_args.items() %} {% for flt_name, flt_value in filter_args.items() %}
<input type="hidden" name="{{ flt_name }}" value="{{ flt_value }}"> <input type="hidden" name="{{ flt_name }}" value="{{ flt_value }}">
{% endfor %} {% endfor %}
{% for arg_name, arg_value in extra_args.items() %}
<input type="hidden" name="{{ arg_name }}" value="{{ arg_value }}">
{% endfor %}
{% if page_size != default_page_size %} {% if page_size != default_page_size %}
<input type="hidden" name="page_size" value="{{ page_size }}"> <input type="hidden" name="page_size" value="{{ page_size }}">
{% endif %} {% endif %}
......
...@@ -436,6 +436,47 @@ def test_column_searchable_list(): ...@@ -436,6 +436,47 @@ def test_column_searchable_list():
ok_('model2-test' in data) ok_('model2-test' in data)
def test_extra_args_search():
app, db, admin = setup()
Model1, Model2 = create_models(db)
view1 = CustomModelView(Model1, db.session,
column_searchable_list=['test1', ])
admin.add_view(view1)
db.session.add(Model2('model1-test', ))
db.session.commit()
client = app.test_client()
# check that extra args in the url are propagated as hidden fields in the search form
rv = client.get('/admin/model1/?search=model1&foo=bar')
data = rv.data.decode('utf-8')
ok_('<input type="hidden" name="foo" value="bar">' in data)
def test_extra_args_filter():
app, db, admin = setup()
Model1, Model2 = create_models(db)
view2 = CustomModelView(Model2, db.session,
column_filters=['int_field', ])
admin.add_view(view2)
db.session.add(Model2('model2-test', 5000))
db.session.commit()
client = app.test_client()
# check that extra args in the url are propagated as hidden fields in the form
rv = client.get('/admin/model2/?flt1_0=5000&foo=bar')
data = rv.data.decode('utf-8')
ok_('<input type="hidden" name="foo" value="bar">' in data)
def test_complex_searchable_list(): def test_complex_searchable_list():
app, db, admin = setup() app, db, admin = setup()
......
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