feat; add single-column sorting (frontend or backend) for grids
This commit is contained in:
parent
f21efbab9f
commit
58f7a862a2
10 changed files with 1215 additions and 100 deletions
|
@ -3,11 +3,13 @@
|
|||
from unittest import TestCase
|
||||
from unittest.mock import patch
|
||||
|
||||
from sqlalchemy import orm
|
||||
from paginate import Page
|
||||
from paginate_sqlalchemy import SqlalchemyOrmPage
|
||||
from pyramid import testing
|
||||
|
||||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttaweb.grids import base
|
||||
from wuttaweb.grids import base as mod
|
||||
from wuttaweb.forms import FieldList
|
||||
from tests.util import WebTestCase
|
||||
|
||||
|
@ -15,7 +17,7 @@ from tests.util import WebTestCase
|
|||
class TestGrid(WebTestCase):
|
||||
|
||||
def make_grid(self, request=None, **kwargs):
|
||||
return base.Grid(request or self.request, **kwargs)
|
||||
return mod.Grid(request or self.request, **kwargs)
|
||||
|
||||
def test_constructor(self):
|
||||
|
||||
|
@ -30,6 +32,50 @@ class TestGrid(WebTestCase):
|
|||
self.assertIsInstance(grid.columns, FieldList)
|
||||
self.assertEqual(grid.columns, ['foo', 'bar'])
|
||||
|
||||
def test_constructor_sorting(self):
|
||||
model = self.app.model
|
||||
|
||||
# defaults, not sortable
|
||||
grid = self.make_grid()
|
||||
self.assertFalse(grid.sortable)
|
||||
self.assertTrue(grid.sort_on_backend)
|
||||
self.assertEqual(grid.sorters, {})
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
|
||||
# defaults, sortable
|
||||
grid = self.make_grid(sortable=True)
|
||||
self.assertTrue(grid.sortable)
|
||||
self.assertTrue(grid.sort_on_backend)
|
||||
self.assertEqual(grid.sorters, {})
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
|
||||
# sorters may be pre-populated
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True)
|
||||
self.assertEqual(len(grid.sorters), 2)
|
||||
self.assertIn('name', grid.sorters)
|
||||
self.assertIn('value', grid.sorters)
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
|
||||
# sort defaults as str
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_defaults='name')
|
||||
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'asc')])
|
||||
|
||||
# sort defaults as tuple
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_defaults=('name', 'desc'))
|
||||
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
|
||||
|
||||
# sort defaults as list w/ single tuple
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_defaults=[('name', 'desc')])
|
||||
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
|
||||
|
||||
# sort defaults as list w/ multiple
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_defaults=[('name', 'desc'), ('value', 'asc')])
|
||||
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'desc')])
|
||||
|
||||
def test_vue_tagname(self):
|
||||
grid = self.make_grid()
|
||||
self.assertEqual(grid.vue_tagname, 'wutta-grid')
|
||||
|
@ -174,6 +220,9 @@ class TestGrid(WebTestCase):
|
|||
##############################
|
||||
|
||||
def test_load_settings(self):
|
||||
model = self.app.model
|
||||
|
||||
# nb. first use a paging grid
|
||||
grid = self.make_grid(key='foo', paginated=True, paginate_on_backend=True,
|
||||
pagesize=20, page=1)
|
||||
|
||||
|
@ -196,19 +245,169 @@ class TestGrid(WebTestCase):
|
|||
grid.load_settings()
|
||||
self.assertFalse(grid.paginated)
|
||||
|
||||
# nb. next use a sorting grid
|
||||
grid = self.make_grid(key='settings', model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True)
|
||||
|
||||
# settings are loaded, applied, saved
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
self.request.GET = {'sort1key': 'name', 'sort1dir': 'desc'}
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'desc'}])
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.length'], 1)
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.key'], 'name')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.dir'], 'desc')
|
||||
|
||||
# can skip the saving step
|
||||
self.request.GET = {'sort1key': 'name', 'sort1dir': 'asc'}
|
||||
grid.load_settings(store=False)
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.length'], 1)
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.key'], 'name')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.dir'], 'desc')
|
||||
|
||||
# no error for non-sortable grid
|
||||
grid = self.make_grid(key='foo', sortable=False)
|
||||
grid.load_settings()
|
||||
self.assertFalse(grid.sortable)
|
||||
|
||||
# with sort defaults
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_on_backend=True, sort_defaults='name')
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
|
||||
|
||||
# with multi-column sort defaults
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True,
|
||||
sort_on_backend=True)
|
||||
grid.sort_defaults = [
|
||||
mod.SortInfo('name', 'asc'),
|
||||
mod.SortInfo('value', 'desc'),
|
||||
]
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'asc'}])
|
||||
|
||||
# load settings from session when nothing is in request
|
||||
self.request.GET = {}
|
||||
self.request.session.invalidate()
|
||||
self.assertNotIn('grid.settings.sorters.length', self.request.session)
|
||||
self.request.session['grid.settings.sorters.length'] = 1
|
||||
self.request.session['grid.settings.sorters.1.key'] = 'name'
|
||||
self.request.session['grid.settings.sorters.1.dir'] = 'desc'
|
||||
grid = self.make_grid(key='settings', model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True,
|
||||
paginated=True, paginate_on_backend=True)
|
||||
self.assertFalse(hasattr(grid, 'active_sorters'))
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.active_sorters, [{'key': 'name', 'dir': 'desc'}])
|
||||
|
||||
def test_request_has_settings(self):
|
||||
grid = self.make_grid(key='foo')
|
||||
|
||||
self.assertFalse(grid.request_has_settings())
|
||||
|
||||
# paging
|
||||
self.assertFalse(grid.request_has_settings('page'))
|
||||
with patch.object(self.request, 'GET', new={'pagesize': '20'}):
|
||||
self.assertTrue(grid.request_has_settings())
|
||||
|
||||
self.assertTrue(grid.request_has_settings('page'))
|
||||
with patch.object(self.request, 'GET', new={'page': '1'}):
|
||||
self.assertTrue(grid.request_has_settings())
|
||||
self.assertTrue(grid.request_has_settings('page'))
|
||||
|
||||
# sorting
|
||||
self.assertFalse(grid.request_has_settings('sort'))
|
||||
with patch.object(self.request, 'GET', new={'sort1key': 'name'}):
|
||||
self.assertTrue(grid.request_has_settings('sort'))
|
||||
|
||||
def test_get_setting(self):
|
||||
grid = self.make_grid(key='foo')
|
||||
settings = {}
|
||||
|
||||
# default is null
|
||||
value = grid.get_setting(settings, 'pagesize')
|
||||
self.assertIsNone(value)
|
||||
|
||||
# can read value from user session
|
||||
self.request.session['grid.foo.pagesize'] = 15
|
||||
value = grid.get_setting(settings, 'pagesize', src='session')
|
||||
self.assertEqual(value, 15)
|
||||
|
||||
# string value not normalized
|
||||
self.request.session['grid.foo.pagesize'] = '15'
|
||||
value = grid.get_setting(settings, 'pagesize', src='session')
|
||||
self.assertEqual(value, '15')
|
||||
self.assertNotEqual(value, 15)
|
||||
|
||||
# but can be normalized
|
||||
self.request.session['grid.foo.pagesize'] = '15'
|
||||
value = grid.get_setting(settings, 'pagesize', src='session', normalize=int)
|
||||
self.assertEqual(value, 15)
|
||||
|
||||
# can read value from request
|
||||
self.request.GET = {'pagesize': '25'}
|
||||
value = grid.get_setting(settings, 'pagesize', src='request', normalize=int)
|
||||
self.assertEqual(value, 25)
|
||||
|
||||
# null when normalization fails
|
||||
self.request.GET = {'pagesize': 'invalid'}
|
||||
value = grid.get_setting(settings, 'pagesize', src='request', normalize=int)
|
||||
self.assertIsNone(value)
|
||||
|
||||
# reset
|
||||
del self.request.session['grid.foo.pagesize']
|
||||
self.request.GET = {}
|
||||
|
||||
# value can come from provided settings
|
||||
settings['pagesize'] = '35'
|
||||
value = grid.get_setting(settings, 'pagesize', src='session', normalize=int)
|
||||
self.assertEqual(value, 35)
|
||||
|
||||
def test_update_sort_settings(self):
|
||||
model = self.app.model
|
||||
|
||||
# nothing happens if not sortable
|
||||
grid = self.make_grid(key='settings', model_class=model.Setting)
|
||||
settings = {'sorters.length': 0}
|
||||
self.request.session['grid.settings.sorters.length'] = 1
|
||||
self.request.session['grid.settings.sorters.1.key'] = 'name'
|
||||
self.request.session['grid.settings.sorters.1.dir'] = 'asc'
|
||||
grid.update_sort_settings(settings, src='session')
|
||||
self.assertEqual(settings['sorters.length'], 0)
|
||||
|
||||
# nb. now use a sortable grid
|
||||
grid = self.make_grid(key='settings', model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True)
|
||||
|
||||
# settings are updated from session
|
||||
settings = {'sorters.length': 1, 'sorters.1.key': 'name', 'sorters.1.dir': 'asc'}
|
||||
self.request.session['grid.settings.sorters.length'] = 1
|
||||
self.request.session['grid.settings.sorters.1.key'] = 'name'
|
||||
self.request.session['grid.settings.sorters.1.dir'] = 'asc'
|
||||
grid.update_sort_settings(settings, src='session')
|
||||
self.assertEqual(settings['sorters.length'], 1)
|
||||
self.assertEqual(settings['sorters.1.key'], 'name')
|
||||
self.assertEqual(settings['sorters.1.dir'], 'asc')
|
||||
|
||||
# settings are updated from request
|
||||
self.request.GET = {'sort1key': 'value', 'sort1dir': 'desc'}
|
||||
grid.update_sort_settings(settings, src='request')
|
||||
self.assertEqual(settings['sorters.length'], 1)
|
||||
self.assertEqual(settings['sorters.1.key'], 'value')
|
||||
self.assertEqual(settings['sorters.1.dir'], 'desc')
|
||||
|
||||
def test_update_page_settings(self):
|
||||
|
||||
# nothing happens if not paginated
|
||||
grid = self.make_grid(key='foo')
|
||||
settings = {'pagesize': 20, 'page': 1}
|
||||
self.request.session['grid.foo.pagesize'] = 10
|
||||
self.request.session['grid.foo.page'] = 2
|
||||
grid.update_page_settings(settings)
|
||||
self.assertEqual(settings['pagesize'], 20)
|
||||
self.assertEqual(settings['page'], 1)
|
||||
|
||||
# nb. now use a paginated grid
|
||||
grid = self.make_grid(key='foo', paginated=True, paginate_on_backend=True)
|
||||
|
||||
# settings are updated from session
|
||||
settings = {'pagesize': 20, 'page': 1}
|
||||
|
@ -225,52 +424,370 @@ class TestGrid(WebTestCase):
|
|||
self.assertEqual(settings['page'], 4)
|
||||
|
||||
def test_persist_settings(self):
|
||||
model = self.app.model
|
||||
|
||||
# nb. start out with paginated-only grid
|
||||
grid = self.make_grid(key='foo', paginated=True, paginate_on_backend=True)
|
||||
|
||||
# invalid dest
|
||||
self.assertRaises(ValueError, grid.persist_settings, {}, dest='doesnotexist')
|
||||
|
||||
# nb. no error if empty settings, but it saves null values
|
||||
grid.persist_settings({})
|
||||
grid.persist_settings({}, dest='session')
|
||||
self.assertIsNone(self.request.session['grid.foo.page'])
|
||||
|
||||
# provided values are saved
|
||||
grid.persist_settings({'pagesize': 15, 'page': 3})
|
||||
grid.persist_settings({'pagesize': 15, 'page': 3}, dest='session')
|
||||
self.assertEqual(self.request.session['grid.foo.page'], 3)
|
||||
|
||||
# nb. now switch to sortable-only grid
|
||||
grid = self.make_grid(key='settings', model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True)
|
||||
|
||||
# no error if empty settings; does not save values
|
||||
grid.persist_settings({}, dest='session')
|
||||
self.assertNotIn('grid.settings.sorters.length', self.request.session)
|
||||
|
||||
# provided values are saved
|
||||
grid.persist_settings({'sorters.length': 2,
|
||||
'sorters.1.key': 'name',
|
||||
'sorters.1.dir': 'desc',
|
||||
'sorters.2.key': 'value',
|
||||
'sorters.2.dir': 'asc'},
|
||||
dest='session')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.length'], 2)
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.key'], 'name')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.dir'], 'desc')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.2.key'], 'value')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.2.dir'], 'asc')
|
||||
|
||||
# old values removed when new are saved
|
||||
grid.persist_settings({'sorters.length': 1,
|
||||
'sorters.1.key': 'name',
|
||||
'sorters.1.dir': 'desc'},
|
||||
dest='session')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.length'], 1)
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.key'], 'name')
|
||||
self.assertEqual(self.request.session['grid.settings.sorters.1.dir'], 'desc')
|
||||
self.assertNotIn('grid.settings.sorters.2.key', self.request.session)
|
||||
self.assertNotIn('grid.settings.sorters.2.dir', self.request.session)
|
||||
|
||||
##############################
|
||||
# sorting methods
|
||||
##############################
|
||||
|
||||
def test_make_backend_sorters(self):
|
||||
model = self.app.model
|
||||
|
||||
# default is empty
|
||||
grid = self.make_grid()
|
||||
sorters = grid.make_backend_sorters()
|
||||
self.assertEqual(sorters, {})
|
||||
|
||||
# makes sorters if model class
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorters = grid.make_backend_sorters()
|
||||
self.assertEqual(len(sorters), 2)
|
||||
self.assertIn('name', sorters)
|
||||
self.assertIn('value', sorters)
|
||||
|
||||
# does not replace supplied sorters
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
mysorters = {'value': 42}
|
||||
sorters = grid.make_backend_sorters(mysorters)
|
||||
self.assertEqual(len(sorters), 2)
|
||||
self.assertIn('name', sorters)
|
||||
self.assertIn('value', sorters)
|
||||
self.assertEqual(sorters['value'], 42)
|
||||
self.assertEqual(mysorters['value'], 42)
|
||||
|
||||
def test_make_sorter(self):
|
||||
model = self.app.model
|
||||
sample_data = [
|
||||
{'name': 'foo1', 'value': 'ONE'},
|
||||
{'name': 'foo2', 'value': 'two'},
|
||||
{'name': 'foo3', 'value': 'three'},
|
||||
{'name': 'foo4', 'value': 'four'},
|
||||
{'name': 'foo5', 'value': 'five'},
|
||||
{'name': 'foo6', 'value': 'six'},
|
||||
{'name': 'foo7', 'value': 'seven'},
|
||||
{'name': 'foo8', 'value': 'eight'},
|
||||
{'name': 'foo9', 'value': 'nine'},
|
||||
]
|
||||
for setting in sample_data:
|
||||
self.app.save_setting(self.session, setting['name'], setting['value'])
|
||||
self.session.commit()
|
||||
sample_query = self.session.query(model.Setting)
|
||||
|
||||
# plain data
|
||||
grid = self.make_grid(columns=['name', 'value'])
|
||||
sorter = grid.make_sorter('name')
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo9', 'value': 'nine'})
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# model class, but still plain data
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter('name')
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo9', 'value': 'nine'})
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# repeat previous test, w/ model property
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter(model.Setting.name)
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo9', 'value': 'nine'})
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(sorted_data[0], {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# sqlalchemy query
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter('name')
|
||||
sorted_query = sorter(sample_query, 'desc')
|
||||
sorted_data = sorted_query.all()
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo9', 'value': 'nine'})
|
||||
sorted_query = sorter(sample_query, 'asc')
|
||||
sorted_data = sorted_query.all()
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# repeat previous test, w/ model property
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter(model.Setting.name)
|
||||
sorted_query = sorter(sample_query, 'desc')
|
||||
sorted_data = sorted_query.all()
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo9', 'value': 'nine'})
|
||||
sorted_query = sorter(sample_query, 'asc')
|
||||
sorted_data = sorted_query.all()
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# sortfunc for "invalid" column will fail when called; however
|
||||
# it can work for manual sort w/ custom keyfunc
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter('doesnotexist')
|
||||
self.assertRaises(TypeError, sorter, sample_query, 'desc')
|
||||
self.assertRaises(KeyError, sorter, sample_data, 'desc')
|
||||
sorter = grid.make_sorter('doesnotexist', keyfunc=lambda obj: obj['name'])
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(len(sorted_data), 9)
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(len(sorted_data), 9)
|
||||
|
||||
# case folding is off by default
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter('value')
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo2', 'value': 'two'})
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo1', 'value': 'ONE'})
|
||||
|
||||
# results are different with case folding
|
||||
grid = self.make_grid(model_class=model.Setting)
|
||||
sorter = grid.make_sorter('value', foldcase=True)
|
||||
sorted_data = sorter(sample_data, 'desc')
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo2', 'value': 'two'})
|
||||
sorted_data = sorter(sample_data, 'asc')
|
||||
self.assertEqual(dict(sorted_data[0]), {'name': 'foo8', 'value': 'eight'})
|
||||
|
||||
def test_set_sorter(self):
|
||||
model = self.app.model
|
||||
|
||||
# explicit sortfunc
|
||||
grid = self.make_grid()
|
||||
self.assertEqual(grid.sorters, {})
|
||||
sortfunc = lambda data, direction: data
|
||||
grid.set_sorter('foo', sortfunc)
|
||||
self.assertIs(grid.sorters['foo'], sortfunc)
|
||||
|
||||
# auto from model property
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True, sorters={})
|
||||
self.assertEqual(grid.sorters, {})
|
||||
grid.set_sorter('name', model.Setting.name)
|
||||
self.assertTrue(callable(grid.sorters['name']))
|
||||
|
||||
# auto from column name
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True, sorters={})
|
||||
self.assertEqual(grid.sorters, {})
|
||||
grid.set_sorter('name', 'name')
|
||||
self.assertTrue(callable(grid.sorters['name']))
|
||||
|
||||
# auto from key
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True, sorters={})
|
||||
self.assertEqual(grid.sorters, {})
|
||||
grid.set_sorter('name')
|
||||
self.assertTrue(callable(grid.sorters['name']))
|
||||
|
||||
def test_remove_sorter(self):
|
||||
model = self.app.model
|
||||
|
||||
# basics
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True)
|
||||
self.assertEqual(len(grid.sorters), 2)
|
||||
self.assertIn('name', grid.sorters)
|
||||
self.assertIn('value', grid.sorters)
|
||||
grid.remove_sorter('value')
|
||||
self.assertNotIn('value', grid.sorters)
|
||||
|
||||
def test_set_sort_defaults(self):
|
||||
model = self.app.model
|
||||
|
||||
# basics
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True)
|
||||
self.assertEqual(grid.sort_defaults, [])
|
||||
grid.set_sort_defaults('name', 'asc')
|
||||
self.assertEqual(grid.sort_defaults, [mod.SortInfo('name', 'asc')])
|
||||
|
||||
def test_is_sortable(self):
|
||||
model = self.app.model
|
||||
|
||||
# basics, frontend sorting
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True, sort_on_backend=False)
|
||||
self.assertTrue(grid.is_sortable('name'))
|
||||
self.assertTrue(grid.is_sortable('value'))
|
||||
grid.remove_sorter('value')
|
||||
# nb. columns are always sortable for frontend, despite remove_sorter()
|
||||
self.assertTrue(grid.is_sortable('value'))
|
||||
# nb. when grid is not sortable, no column is either
|
||||
grid.sortable = False
|
||||
self.assertFalse(grid.is_sortable('name'))
|
||||
|
||||
# same test but with backend sorting
|
||||
grid = self.make_grid(model_class=model.Setting, sortable=True, sort_on_backend=True)
|
||||
self.assertTrue(grid.is_sortable('name'))
|
||||
self.assertTrue(grid.is_sortable('value'))
|
||||
grid.remove_sorter('value')
|
||||
self.assertFalse(grid.is_sortable('value'))
|
||||
# nb. when grid is not sortable, no column is either
|
||||
grid.sortable = False
|
||||
self.assertFalse(grid.is_sortable('name'))
|
||||
|
||||
##############################
|
||||
# data methods
|
||||
##############################
|
||||
|
||||
def test_get_visible_data(self):
|
||||
data = [
|
||||
{'foo': 1, 'bar': 1},
|
||||
{'foo': 2, 'bar': 2},
|
||||
{'foo': 3, 'bar': 3},
|
||||
{'foo': 4, 'bar': 4},
|
||||
{'foo': 5, 'bar': 5},
|
||||
{'foo': 6, 'bar': 6},
|
||||
{'foo': 7, 'bar': 7},
|
||||
{'foo': 8, 'bar': 8},
|
||||
{'foo': 9, 'bar': 9},
|
||||
model = self.app.model
|
||||
sample_data = [
|
||||
{'name': 'foo1', 'value': 'ONE'},
|
||||
{'name': 'foo2', 'value': 'two'},
|
||||
{'name': 'foo3', 'value': 'three'},
|
||||
{'name': 'foo4', 'value': 'four'},
|
||||
{'name': 'foo5', 'value': 'five'},
|
||||
{'name': 'foo6', 'value': 'six'},
|
||||
{'name': 'foo7', 'value': 'seven'},
|
||||
{'name': 'foo8', 'value': 'eight'},
|
||||
{'name': 'foo9', 'value': 'nine'},
|
||||
]
|
||||
grid = self.make_grid(data=data,
|
||||
columns=['foo', 'bar'],
|
||||
for setting in sample_data:
|
||||
self.app.save_setting(self.session, setting['name'], setting['value'])
|
||||
self.session.commit()
|
||||
sample_query = self.session.query(model.Setting)
|
||||
|
||||
# data is sorted and paginated
|
||||
grid = self.make_grid(model_class=model.Setting,
|
||||
data=sample_query,
|
||||
sortable=True, sort_on_backend=True,
|
||||
sort_defaults=('name', 'desc'),
|
||||
paginated=True, paginate_on_backend=True,
|
||||
pagesize=4, page=2)
|
||||
grid.load_settings()
|
||||
visible = grid.get_visible_data()
|
||||
self.assertEqual(len(visible), 4)
|
||||
self.assertEqual(visible[0], {'foo': 5, 'bar': 5})
|
||||
self.assertEqual([s.name for s in visible], ['foo5', 'foo4', 'foo3', 'foo2'])
|
||||
|
||||
def test_sort_data(self):
|
||||
model = self.app.model
|
||||
sample_data = [
|
||||
{'name': 'foo1', 'value': 'ONE'},
|
||||
{'name': 'foo2', 'value': 'two'},
|
||||
{'name': 'foo3', 'value': 'three'},
|
||||
{'name': 'foo4', 'value': 'four'},
|
||||
{'name': 'foo5', 'value': 'five'},
|
||||
{'name': 'foo6', 'value': 'six'},
|
||||
{'name': 'foo7', 'value': 'seven'},
|
||||
{'name': 'foo8', 'value': 'eight'},
|
||||
{'name': 'foo9', 'value': 'nine'},
|
||||
]
|
||||
for setting in sample_data:
|
||||
self.app.save_setting(self.session, setting['name'], setting['value'])
|
||||
self.session.commit()
|
||||
sample_query = self.session.query(model.Setting)
|
||||
|
||||
grid = self.make_grid(model_class=model.Setting,
|
||||
sortable=True, sort_on_backend=True,
|
||||
sort_defaults=('name', 'desc'))
|
||||
grid.load_settings()
|
||||
|
||||
# can sort a simple list of data
|
||||
sorted_data = grid.sort_data(sample_data)
|
||||
self.assertIsInstance(sorted_data, list)
|
||||
self.assertEqual(len(sorted_data), 9)
|
||||
self.assertEqual(sorted_data[0]['name'], 'foo9')
|
||||
self.assertEqual(sorted_data[-1]['name'], 'foo1')
|
||||
|
||||
# can also sort a data query
|
||||
sorted_query = grid.sort_data(sample_query)
|
||||
self.assertIsInstance(sorted_query, orm.Query)
|
||||
sorted_data = sorted_query.all()
|
||||
self.assertEqual(len(sorted_data), 9)
|
||||
self.assertEqual(sorted_data[0]['name'], 'foo9')
|
||||
self.assertEqual(sorted_data[-1]['name'], 'foo1')
|
||||
|
||||
# cannot sort data if sorter missing in overrides
|
||||
sorted_data = grid.sort_data(sample_data, sorters=[])
|
||||
# nb. sorted data is in same order as original sample (not sorted)
|
||||
self.assertEqual(sorted_data[0]['name'], 'foo1')
|
||||
self.assertEqual(sorted_data[-1]['name'], 'foo9')
|
||||
|
||||
# error if mult-column sort attempted
|
||||
self.assertRaises(NotImplementedError, grid.sort_data, sample_data, sorters=[
|
||||
{'key': 'name', 'dir': 'desc'},
|
||||
{'key': 'value', 'dir': 'asc'},
|
||||
])
|
||||
|
||||
# cannot sort data if sortfunc is missing for column
|
||||
grid.remove_sorter('name')
|
||||
sorted_data = grid.sort_data(sample_data)
|
||||
# nb. sorted data is in same order as original sample (not sorted)
|
||||
self.assertEqual(sorted_data[0]['name'], 'foo1')
|
||||
self.assertEqual(sorted_data[-1]['name'], 'foo9')
|
||||
|
||||
def test_paginate_data(self):
|
||||
grid = self.make_grid()
|
||||
pager = grid.paginate_data([])
|
||||
model = self.app.model
|
||||
sample_data = [
|
||||
{'name': 'foo1', 'value': 'ONE'},
|
||||
{'name': 'foo2', 'value': 'two'},
|
||||
{'name': 'foo3', 'value': 'three'},
|
||||
{'name': 'foo4', 'value': 'four'},
|
||||
{'name': 'foo5', 'value': 'five'},
|
||||
{'name': 'foo6', 'value': 'six'},
|
||||
{'name': 'foo7', 'value': 'seven'},
|
||||
{'name': 'foo8', 'value': 'eight'},
|
||||
{'name': 'foo9', 'value': 'nine'},
|
||||
]
|
||||
for setting in sample_data:
|
||||
self.app.save_setting(self.session, setting['name'], setting['value'])
|
||||
self.session.commit()
|
||||
sample_query = self.session.query(model.Setting)
|
||||
|
||||
# basic list pager
|
||||
grid = self.make_grid(paginated=True, paginate_on_backend=True)
|
||||
pager = grid.paginate_data(sample_data)
|
||||
self.assertIsInstance(pager, Page)
|
||||
|
||||
# basic query pager
|
||||
grid = self.make_grid(paginated=True, paginate_on_backend=True)
|
||||
pager = grid.paginate_data(sample_query)
|
||||
self.assertIsInstance(pager, SqlalchemyOrmPage)
|
||||
|
||||
# page is reset to 1 for empty data
|
||||
self.request.session['grid.foo.page'] = 2
|
||||
grid = self.make_grid(key='foo', paginated=True, paginate_on_backend=True)
|
||||
grid.load_settings()
|
||||
self.assertEqual(grid.page, 2)
|
||||
self.assertEqual(self.request.session['grid.foo.page'], 2)
|
||||
pager = grid.paginate_data([])
|
||||
pager = grid.paginate_data(sample_data)
|
||||
self.assertEqual(pager.page, 1)
|
||||
self.assertEqual(grid.page, 1)
|
||||
self.assertEqual(self.request.session['grid.foo.page'], 1)
|
||||
|
@ -322,7 +839,7 @@ class TestGrid(WebTestCase):
|
|||
self.assertEqual(data, [{'foo': 'bar'}])
|
||||
|
||||
# if grid has actions, that list may be supplemented
|
||||
grid.actions.append(base.GridAction(self.request, 'view', url='/blarg'))
|
||||
grid.actions.append(mod.GridAction(self.request, 'view', url='/blarg'))
|
||||
data = grid.get_vue_data()
|
||||
self.assertIsNot(data, mydata)
|
||||
self.assertEqual(data, [{'foo': 'bar', '_action_url_view': '/blarg'}])
|
||||
|
@ -362,7 +879,7 @@ class TestGridAction(TestCase):
|
|||
self.request = testing.DummyRequest(wutta_config=self.config, use_oruga=False)
|
||||
|
||||
def make_action(self, key, **kwargs):
|
||||
return base.GridAction(self.request, key, **kwargs)
|
||||
return mod.GridAction(self.request, key, **kwargs)
|
||||
|
||||
def test_render_icon(self):
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue