mirror of
https://github.com/inventree/InvenTree.git
synced 2026-04-14 15:28:52 +00:00
Additional report tags (#11718)
* Add some more convenience functions for report helpers * Add "reverse" tag * Add unit tests * Add lstrip and rstrip * Fix unit tests
This commit is contained in:
@@ -173,8 +173,144 @@ Generate a list of all active customers:
|
|||||||
|
|
||||||
More advanced database filtering should be achieved using a [report plugin](../plugins/mixins/report.md), and adding custom context data to the report template.
|
More advanced database filtering should be achieved using a [report plugin](../plugins/mixins/report.md), and adding custom context data to the report template.
|
||||||
|
|
||||||
|
## List Helpers
|
||||||
|
|
||||||
|
The following helper functions are available for working with list (or list-like) data structures:
|
||||||
|
|
||||||
|
### length
|
||||||
|
|
||||||
|
Return the length of a list (or list-like) data structure. Note that this will also work for other data structures which support the `len()` function, such as strings, dictionaries or querysets:
|
||||||
|
|
||||||
|
::: report.templatetags.report.length
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### first
|
||||||
|
|
||||||
|
Return the first element of a list (or list-like) data structure:
|
||||||
|
|
||||||
|
::: report.templatetags.report.first
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
|
||||||
|
### last
|
||||||
|
|
||||||
|
Return the last element of a list (or list-like) data structure:
|
||||||
|
|
||||||
|
::: report.templatetags.report.last
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### reverse
|
||||||
|
|
||||||
|
Return a list (or list-like) data structure in reverse order:
|
||||||
|
|
||||||
|
::: report.templatetags.report.reverse
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### truncate
|
||||||
|
|
||||||
|
Return a truncated version of a list (or list-like) data structure, containing only the first N elements:
|
||||||
|
|
||||||
|
::: report.templatetags.report.truncate
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
## String Formatting
|
||||||
|
|
||||||
|
### strip
|
||||||
|
|
||||||
|
Return a string with leading and trailing whitespace removed:
|
||||||
|
|
||||||
|
::: report.templatetags.report.strip
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
|
||||||
|
### lstrip
|
||||||
|
|
||||||
|
Return a string with leading whitespace removed:
|
||||||
|
|
||||||
|
::: report.templatetags.report.lstrip
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### rstrip
|
||||||
|
|
||||||
|
Return a string with trailing whitespace removed:
|
||||||
|
|
||||||
|
::: report.templatetags.report.rstrip
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### split
|
||||||
|
|
||||||
|
Return a list of substrings by splitting a string based on a specified separator:
|
||||||
|
|
||||||
|
::: report.templatetags.report.split
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### join
|
||||||
|
|
||||||
|
Return a string by joining a list of strings into a single string, using a specified separator:
|
||||||
|
|
||||||
|
::: report.templatetags.report.join
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### replace
|
||||||
|
|
||||||
|
Return a string where occurrences of a specified substring are replaced with another substring:
|
||||||
|
|
||||||
|
::: report.templatetags.report.replace
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### lowercase
|
||||||
|
|
||||||
|
Return a string with all characters converted to lowercase:
|
||||||
|
|
||||||
|
::: report.templatetags.report.lowercase
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### uppercase
|
||||||
|
|
||||||
|
Return a string with all characters converted to uppercase:
|
||||||
|
|
||||||
|
::: report.templatetags.report.uppercase
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### titlecase
|
||||||
|
|
||||||
|
Return a string with the first character of each word converted to uppercase and the remaining characters converted to lowercase:
|
||||||
|
|
||||||
|
::: report.templatetags.report.titlecase
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
## Number Formatting
|
## Number Formatting
|
||||||
|
|
||||||
|
A number of helper functions are available for formatting numbers in a particular way. These can be used to format numbers according to a particular number of decimal places, or to add leading zeros, for example.
|
||||||
|
|
||||||
### format_number
|
### format_number
|
||||||
|
|
||||||
The helper function `format_number` allows for some common number formatting options. It takes a number (or a number-like string) as an input, as well as some formatting arguments. It returns a *string* containing the formatted number:
|
The helper function `format_number` allows for some common number formatting options. It takes a number (or a number-like string) as an input, as well as some formatting arguments. It returns a *string* containing the formatted number:
|
||||||
|
|||||||
@@ -1036,3 +1036,196 @@ def include_icon_fonts(ttf: bool = False, woff: bool = False):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return mark_safe(icon_class + '\n'.join(fonts))
|
return mark_safe(icon_class + '\n'.join(fonts))
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def lowercase(value: str) -> str:
|
||||||
|
"""Convert a string to lowercase.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be converted
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).lower()
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def uppercase(value: str) -> str:
|
||||||
|
"""Convert a string to uppercase.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be converted
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).upper()
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def titlecase(value: str) -> str:
|
||||||
|
"""Convert a string to title case.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be converted
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).title()
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def strip(value: str, chars: Optional[str] = ' ') -> str:
|
||||||
|
"""Strip leading and trailing characters from a string.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be stripped
|
||||||
|
chars: The set of characters to strip from the string (default = whitespace)
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).strip(chars)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def lstrip(value: str, chars: Optional[str] = ' ') -> str:
|
||||||
|
"""Strip leading characters from a string.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be stripped
|
||||||
|
chars: The set of characters to strip from the string (default = whitespace)
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).lstrip(chars)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def rstrip(value: str, chars: Optional[str] = ' ') -> str:
|
||||||
|
"""Strip trailing characters from a string.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be stripped
|
||||||
|
chars: The set of characters to strip from the string (default = whitespace)
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).rstrip(chars)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def split(value: str, separator: str = ',') -> list:
|
||||||
|
"""Split a string into a list, using the provided separator (default = ',').
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The string to be split
|
||||||
|
separator: The character to use as a separator (default = ',')
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return []
|
||||||
|
return [v.strip() for v in str(value).split(separator)]
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def join(value: list, separator: str = ',') -> str:
|
||||||
|
"""Join a list of items into a string, using the provided separator (default = ',').
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The list of items to be joined
|
||||||
|
separator: The character to use as a separator (default = ',')
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return separator.join(str(v) for v in value)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def length(value: Any) -> int:
|
||||||
|
"""Return the length of a list or string.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The value to be measured (e.g. a list or string)
|
||||||
|
"""
|
||||||
|
if value is None:
|
||||||
|
return 0
|
||||||
|
try:
|
||||||
|
return len(value)
|
||||||
|
except TypeError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def replace(value: str, old: str, new: str = '') -> str:
|
||||||
|
"""Replace occurrences of a substring within a string with a new value.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The original string
|
||||||
|
old: The substring to be replaced
|
||||||
|
new: The value to replace the old substring with (default = "")
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return ''
|
||||||
|
return str(value).replace(old, new)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def first(value: list, default: Any = None) -> Any:
|
||||||
|
"""Return the first item in a list, or a default value if the list is empty.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The list from which to retrieve the first item
|
||||||
|
default: The value to return if the list is empty (default = None)
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return default
|
||||||
|
try:
|
||||||
|
return value[0]
|
||||||
|
except (IndexError, TypeError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def last(value: list, default: Any = None) -> Any:
|
||||||
|
"""Return the last item in a list, or a default value if the list is empty.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The list from which to retrieve the last item
|
||||||
|
default: The value to return if the list is empty (default = None)
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return default
|
||||||
|
try:
|
||||||
|
return value[-1]
|
||||||
|
except (IndexError, TypeError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def reverse(value: list) -> list:
|
||||||
|
"""Return a reversed version of the provided list.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The list to be reversed
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
return value[::-1]
|
||||||
|
except TypeError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def truncate(value: list, length: int) -> list:
|
||||||
|
"""Return a truncated version of the provided list.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value: The list to be truncated
|
||||||
|
length: The maximum length of the returned list
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
return value[:length]
|
||||||
|
except TypeError:
|
||||||
|
return []
|
||||||
|
|||||||
@@ -231,6 +231,47 @@ class ReportTagTest(PartImageTestMixin, InvenTreeTestCase):
|
|||||||
logo = report_tags.logo_image()
|
logo = report_tags.logo_image()
|
||||||
self.assertIn('inventree.png', logo)
|
self.assertIn('inventree.png', logo)
|
||||||
|
|
||||||
|
def test_string_tags(self):
|
||||||
|
"""Simple tests for the string manipulation tags."""
|
||||||
|
self.assertEqual(report_tags.uppercase('hello world'), 'HELLO WORLD')
|
||||||
|
self.assertEqual(report_tags.lowercase('HELLO WORLD'), 'hello world')
|
||||||
|
self.assertEqual(report_tags.titlecase('hello world'), 'Hello World')
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.strip(' hello world '), 'hello world') # noqa: B005
|
||||||
|
self.assertEqual(report_tags.strip(' hello world ', chars=' hd'), 'ello worl') # noqa: B005
|
||||||
|
self.assertEqual(report_tags.strip('xxhelloxx', chars='xy'), 'hello') # noqa: B005
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.lstrip(' hello world '), 'hello world ') # noqa: B005
|
||||||
|
self.assertEqual(report_tags.rstrip(' world ', chars=' dl'), ' wor') # noqa: B005
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.split('a,b,c', separator=','), ['a', 'b', 'c'])
|
||||||
|
self.assertEqual(report_tags.split('a,|,b|c', separator='|'), ['a,', ',b', 'c'])
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.join(['a', 'b', 'c'], separator=','), 'a,b,c')
|
||||||
|
self.assertEqual(report_tags.join(['a', 'b', 'c'], separator='|'), 'a|b|c')
|
||||||
|
self.assertEqual(report_tags.join(None, separator=','), '')
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.replace('hello world', 'world'), 'hello ')
|
||||||
|
self.assertEqual(
|
||||||
|
report_tags.replace('hello world', 'world', 'there'), 'hello there'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(report_tags.first('hello world'), 'h')
|
||||||
|
self.assertEqual(report_tags.last('hello world'), 'd')
|
||||||
|
self.assertEqual(report_tags.length('hello world'), 11)
|
||||||
|
self.assertEqual(report_tags.truncate('hello world', length=3), 'hel')
|
||||||
|
self.assertEqual(report_tags.reverse('hello world'), 'dlrow olleh')
|
||||||
|
|
||||||
|
def test_list_tags(self):
|
||||||
|
"""Simple tests for list manipulation tags."""
|
||||||
|
self.assertEqual(report_tags.first([1, 2, 3]), 1)
|
||||||
|
self.assertEqual(report_tags.last([1, 2, 3]), 3)
|
||||||
|
self.assertEqual(report_tags.length([1, 2, 3]), 3)
|
||||||
|
self.assertEqual(report_tags.reverse([1, 2, 3]), [3, 2, 1])
|
||||||
|
self.assertEqual(report_tags.truncate([1, 2, 3], 2), [1, 2])
|
||||||
|
self.assertEqual(report_tags.join([1, 2, 3], separator=','), '1,2,3')
|
||||||
|
self.assertEqual(report_tags.join(None, separator=','), '')
|
||||||
|
|
||||||
def test_maths_tags(self):
|
def test_maths_tags(self):
|
||||||
"""Simple tests for mathematical operator tags."""
|
"""Simple tests for mathematical operator tags."""
|
||||||
self.assertEqual(report_tags.add(1, 2), 3)
|
self.assertEqual(report_tags.add(1, 2), 3)
|
||||||
|
|||||||
Reference in New Issue
Block a user