fix: add grid renderers for bool, currency, quantity
also set bool renderer by default when possible
This commit is contained in:
parent
08a895a07b
commit
a612bf3846
|
@ -116,7 +116,8 @@ class Grid:
|
||||||
|
|
||||||
Dict of column (cell) value renderer overrides.
|
Dict of column (cell) value renderer overrides.
|
||||||
|
|
||||||
See also :meth:`set_renderer()`.
|
See also :meth:`set_renderer()` and
|
||||||
|
:meth:`set_default_renderers()`.
|
||||||
|
|
||||||
.. attribute:: row_class
|
.. attribute:: row_class
|
||||||
|
|
||||||
|
@ -602,15 +603,18 @@ class Grid:
|
||||||
"""
|
"""
|
||||||
Set default column value renderers, where applicable.
|
Set default column value renderers, where applicable.
|
||||||
|
|
||||||
This will add new entries to :attr:`renderers` for columns
|
This is called automatically from the class constructor. It
|
||||||
whose data type implies a default renderer should be used.
|
will add new entries to :attr:`renderers` for columns whose
|
||||||
This is generally only possible if :attr:`model_class` is set
|
data type implies a default renderer. This is only possible
|
||||||
to a valid SQLAlchemy mapped class.
|
if :attr:`model_class` is set to a SQLAlchemy mapped class.
|
||||||
|
|
||||||
This (for now?) only looks for
|
This only looks for a couple of data types, and configures as
|
||||||
:class:`sqlalchemy:sqlalchemy.types.DateTime` columns and if
|
follows:
|
||||||
any are found, they are configured to use
|
|
||||||
:meth:`render_datetime()`.
|
* :class:`sqlalchemy:sqlalchemy.types.Boolean` ->
|
||||||
|
:meth:`render_boolean()`
|
||||||
|
* :class:`sqlalchemy:sqlalchemy.types.DateTime` ->
|
||||||
|
:meth:`render_datetime()`
|
||||||
"""
|
"""
|
||||||
if not self.model_class:
|
if not self.model_class:
|
||||||
return
|
return
|
||||||
|
@ -626,6 +630,8 @@ class Grid:
|
||||||
column = prop.columns[0]
|
column = prop.columns[0]
|
||||||
if isinstance(column.type, sa.DateTime):
|
if isinstance(column.type, sa.DateTime):
|
||||||
self.set_renderer(key, self.render_datetime)
|
self.set_renderer(key, self.render_datetime)
|
||||||
|
elif isinstance(column.type, sa.Boolean):
|
||||||
|
self.set_renderer(key, self.render_boolean)
|
||||||
|
|
||||||
def set_link(self, key, link=True):
|
def set_link(self, key, link=True):
|
||||||
"""
|
"""
|
||||||
|
@ -1753,23 +1759,65 @@ class Grid:
|
||||||
# rendering methods
|
# rendering methods
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
|
def render_boolean(self, obj, key, value):
|
||||||
|
"""
|
||||||
|
Column renderer for boolean values.
|
||||||
|
|
||||||
|
This calls
|
||||||
|
:meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_boolean()`
|
||||||
|
for the return value.
|
||||||
|
|
||||||
|
This may be used automatically per
|
||||||
|
:meth:`set_default_renderers()` or you can use it explicitly::
|
||||||
|
|
||||||
|
grid.set_renderer('foo', grid.render_boolean)
|
||||||
|
"""
|
||||||
|
return self.app.render_boolean(value)
|
||||||
|
|
||||||
|
def render_currency(self, obj, key, value):
|
||||||
|
"""
|
||||||
|
Column renderer for currency values.
|
||||||
|
|
||||||
|
This calls
|
||||||
|
:meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_currency()`
|
||||||
|
for the return value.
|
||||||
|
|
||||||
|
This is not used automatically but you can use it explicitly::
|
||||||
|
|
||||||
|
grid.set_renderer('foo', grid.render_currency)
|
||||||
|
"""
|
||||||
|
return self.app.render_currency(value)
|
||||||
|
|
||||||
def render_datetime(self, obj, key, value):
|
def render_datetime(self, obj, key, value):
|
||||||
"""
|
"""
|
||||||
Default cell value renderer for
|
Column renderer for :class:`python:datetime.datetime` values.
|
||||||
:class:`sqlalchemy:sqlalchemy.types.DateTime` columns, which
|
|
||||||
calls
|
This calls
|
||||||
:meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_datetime()`
|
:meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_datetime()`
|
||||||
for the return value.
|
for the return value.
|
||||||
|
|
||||||
This may be used automatically per
|
This may be used automatically per
|
||||||
:meth:`set_default_renderers()` or you can use it explicitly
|
:meth:`set_default_renderers()` or you can use it explicitly::
|
||||||
for any :class:`python:datetime.datetime` column with::
|
|
||||||
|
|
||||||
grid.set_renderer('foo', grid.render_datetime)
|
grid.set_renderer('foo', grid.render_datetime)
|
||||||
"""
|
"""
|
||||||
dt = getattr(obj, key)
|
dt = getattr(obj, key)
|
||||||
return self.app.render_datetime(dt)
|
return self.app.render_datetime(dt)
|
||||||
|
|
||||||
|
def render_quantity(self, obj, key, value):
|
||||||
|
"""
|
||||||
|
Column renderer for quantity values.
|
||||||
|
|
||||||
|
This calls
|
||||||
|
:meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_quantity()`
|
||||||
|
for the return value.
|
||||||
|
|
||||||
|
This is not used automatically but you can use it explicitly::
|
||||||
|
|
||||||
|
grid.set_renderer('foo', grid.render_quantity)
|
||||||
|
"""
|
||||||
|
return self.app.render_quantity(value)
|
||||||
|
|
||||||
def render_table_element(
|
def render_table_element(
|
||||||
self,
|
self,
|
||||||
form=None,
|
form=None,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- coding: utf-8; -*-
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import decimal
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
@ -232,6 +233,17 @@ class TestGrid(WebTestCase):
|
||||||
self.assertIn('created', grid.renderers)
|
self.assertIn('created', grid.renderers)
|
||||||
self.assertIs(grid.renderers['created'], myrender)
|
self.assertIs(grid.renderers['created'], myrender)
|
||||||
|
|
||||||
|
# renderer set for boolean mapped field
|
||||||
|
grid = self.make_grid(model_class=model.Upgrade)
|
||||||
|
self.assertIn('executing', grid.renderers)
|
||||||
|
self.assertIsNot(grid.renderers['executing'], myrender)
|
||||||
|
|
||||||
|
# renderer *not* set for boolean, if override present
|
||||||
|
grid = self.make_grid(model_class=model.Upgrade,
|
||||||
|
renderers={'executing': myrender})
|
||||||
|
self.assertIn('executing', grid.renderers)
|
||||||
|
self.assertIs(grid.renderers['executing'], myrender)
|
||||||
|
|
||||||
def test_linked_columns(self):
|
def test_linked_columns(self):
|
||||||
grid = self.make_grid(columns=['foo', 'bar'])
|
grid = self.make_grid(columns=['foo', 'bar'])
|
||||||
self.assertEqual(grid.linked_columns, [])
|
self.assertEqual(grid.linked_columns, [])
|
||||||
|
@ -1331,6 +1343,62 @@ class TestGrid(WebTestCase):
|
||||||
# rendering methods
|
# rendering methods
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
|
def test_render_boolean(self):
|
||||||
|
grid = self.make_grid(columns=['foo', 'bar'])
|
||||||
|
|
||||||
|
# null
|
||||||
|
obj = MagicMock(foo=None)
|
||||||
|
self.assertEqual(grid.render_boolean(obj, 'foo', None), "")
|
||||||
|
|
||||||
|
# true
|
||||||
|
obj = MagicMock(foo=True)
|
||||||
|
self.assertEqual(grid.render_boolean(obj, 'foo', True), "Yes")
|
||||||
|
|
||||||
|
# false
|
||||||
|
obj = MagicMock(foo=False)
|
||||||
|
self.assertEqual(grid.render_boolean(obj, 'foo', False), "No")
|
||||||
|
|
||||||
|
def test_render_currency(self):
|
||||||
|
grid = self.make_grid(columns=['foo', 'bar'])
|
||||||
|
obj = MagicMock()
|
||||||
|
|
||||||
|
# null
|
||||||
|
self.assertEqual(grid.render_currency(obj, 'foo', None), '')
|
||||||
|
|
||||||
|
# basic decimal example
|
||||||
|
value = decimal.Decimal('42.00')
|
||||||
|
self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.00')
|
||||||
|
|
||||||
|
# basic float example
|
||||||
|
value = 42.00
|
||||||
|
self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.00')
|
||||||
|
|
||||||
|
# decimal places will be rounded
|
||||||
|
value = decimal.Decimal('42.12345')
|
||||||
|
self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.12')
|
||||||
|
|
||||||
|
# negative numbers get parens
|
||||||
|
value = decimal.Decimal('-42.42')
|
||||||
|
self.assertEqual(grid.render_currency(obj, 'foo', value), '($42.42)')
|
||||||
|
|
||||||
|
def test_render_quantity(self):
|
||||||
|
grid = self.make_grid(columns=['foo', 'bar'])
|
||||||
|
obj = MagicMock()
|
||||||
|
|
||||||
|
# null
|
||||||
|
self.assertEqual(grid.render_quantity(obj, 'foo', None), "")
|
||||||
|
|
||||||
|
# integer decimals become integers
|
||||||
|
value = decimal.Decimal('1.000')
|
||||||
|
self.assertEqual(grid.render_quantity(obj, 'foo', value), "1")
|
||||||
|
|
||||||
|
# but decimal places are preserved
|
||||||
|
value = decimal.Decimal('1.234')
|
||||||
|
self.assertEqual(grid.render_quantity(obj ,'foo', value), "1.234")
|
||||||
|
|
||||||
|
# zero is *not* empty string (with this renderer)
|
||||||
|
self.assertEqual(grid.render_quantity(obj, 'foo', 0), "0")
|
||||||
|
|
||||||
def test_render_datetime(self):
|
def test_render_datetime(self):
|
||||||
grid = self.make_grid(columns=['foo', 'bar'])
|
grid = self.make_grid(columns=['foo', 'bar'])
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue