kopia lustrzana https://github.com/wagtail/wagtail
Add new FloatBlock, DecimalBlock and a RegexBlock (#2737)
rodzic
334bebc55c
commit
9358e3b611
|
@ -14,6 +14,7 @@ Changelog
|
|||
* The wagtailimages.Filter model has been removed, and converted to a Python class instead (Gagaro)
|
||||
* Multiple ChooserBlocks inside a StreamField are now prefetched in bulk, for improved performance (Michael van Tellingen, Roel Bruggink, Matt Westcott)
|
||||
* Add new EmailBlock and IntegerBlock (Oktay Altay)
|
||||
* Added a new FloatBlock, DecimalBlock and a RegexBlock (Oktay Altay, Andy Babic)
|
||||
* Fix: Email templates and document uploader now support custom `STATICFILES_STORAGE` (Jonny Scholes)
|
||||
* Fix: Removed alignment options (deprecated in HTML and not rendered by Wagtail) from `TableBlock` context menu (Moritz Pfeiffer)
|
||||
* Fix: Fixed incorrect CSS path on ModelAdmin's "choose a parent page" view
|
||||
|
|
|
@ -89,7 +89,6 @@ TextBlock
|
|||
|
||||
A multi-line text input. As with ``CharBlock``, the keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted.
|
||||
|
||||
|
||||
EmailBlock
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -104,6 +103,27 @@ IntegerBlock
|
|||
|
||||
A single-line integer input that validates that the integer is a valid whole number. The keyword arguments ``required``, ``max_length``, ``min_length`` and ``help_text`` are accepted.
|
||||
|
||||
FloatBlock
|
||||
~~~~~~~~~~
|
||||
|
||||
``wagtail.wagtailcore.blocks.FloatBlock``
|
||||
|
||||
A single-line Float input that validates that the value is a valid floating point number. The keyword arguments ``required``, ``max_value`` and ``min_value`` are accepted.
|
||||
|
||||
DecimalBlock
|
||||
~~~~~~~~~~
|
||||
|
||||
``wagtail.wagtailcore.blocks.DecimalBlock``
|
||||
|
||||
A single-line decimal input that validates that the value is a valid decimal number. The keyword arguments ``required``, ``max_value``, ``min_value``, ``max_digits`` and ``decimal_places`` are accepted.
|
||||
|
||||
RegexBlock
|
||||
~~~~~~~~~~
|
||||
|
||||
``wagtail.wagtailcore.blocks.RegexBlock``
|
||||
|
||||
A single-line text input that validates a string against a regex expression. The regular expression used for validation must be supplied as the first argument, or as the keyword argument ``regex``. The message text used to indicate a validation error can be customised using the ``error_message`` keyword argument to pass a custom message. The keyword arguments ``regex``, ``required``, ``max_length``, ``min_length`` and ``error_message`` are accepted.
|
||||
|
||||
URLBlock
|
||||
~~~~~~~~
|
||||
|
||||
|
|
|
@ -129,6 +129,55 @@ class TextBlock(FieldBlock):
|
|||
icon = "pilcrow"
|
||||
|
||||
|
||||
class FloatBlock(FieldBlock):
|
||||
|
||||
def __init__(self, required=True, max_value=None, min_value=None, *args,
|
||||
**kwargs):
|
||||
self.field = forms.FloatField(
|
||||
required=required,
|
||||
max_value=max_value,
|
||||
min_value=min_value,
|
||||
)
|
||||
super(FloatBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
icon = "plus-inverse"
|
||||
|
||||
|
||||
class DecimalBlock(FieldBlock):
|
||||
|
||||
def __init__(self, required=True, max_value=None, min_value=None,
|
||||
max_digits=None, decimal_places=None, *args, **kwargs):
|
||||
self.field = forms.DecimalField(
|
||||
required=required,
|
||||
max_value=max_value,
|
||||
min_value=min_value,
|
||||
max_digits=max_digits,
|
||||
decimal_places=decimal_places,
|
||||
)
|
||||
super(DecimalBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
icon = "plus-inverse"
|
||||
|
||||
|
||||
class RegexBlock(FieldBlock):
|
||||
|
||||
def __init__(self, regex, required=True, max_length=None, min_length=None,
|
||||
error_message=None, *args, **kwargs):
|
||||
self.field = forms.RegexField(
|
||||
regex=regex,
|
||||
required=required,
|
||||
max_length=max_length,
|
||||
min_length=min_length,
|
||||
error_message=error_message,
|
||||
)
|
||||
super(RegexBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
icon = "code"
|
||||
|
||||
|
||||
class URLBlock(FieldBlock):
|
||||
|
||||
def __init__(self, required=True, help_text=None, max_length=None, min_length=None, **kwargs):
|
||||
|
@ -500,8 +549,10 @@ class PageChooserBlock(ChooserBlock):
|
|||
# Ensure that the blocks defined here get deconstructed as wagtailcore.blocks.FooBlock
|
||||
# rather than wagtailcore.blocks.field.FooBlock
|
||||
block_classes = [
|
||||
FieldBlock, CharBlock, URLBlock, RichTextBlock, RawHTMLBlock, ChooserBlock, PageChooserBlock,
|
||||
TextBlock, BooleanBlock, DateBlock, TimeBlock, DateTimeBlock, ChoiceBlock, EmailBlock, IntegerBlock,
|
||||
FieldBlock, CharBlock, URLBlock, RichTextBlock, RawHTMLBlock, ChooserBlock,
|
||||
PageChooserBlock, TextBlock, BooleanBlock, DateBlock, TimeBlock,
|
||||
DateTimeBlock, ChoiceBlock, EmailBlock, IntegerBlock, FloatBlock,
|
||||
DecimalBlock, RegexBlock
|
||||
]
|
||||
DECONSTRUCT_ALIASES = {
|
||||
cls: 'wagtail.wagtailcore.blocks.%s' % cls.__name__
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals
|
|||
|
||||
import base64
|
||||
import unittest
|
||||
from decimal import Decimal
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -29,54 +30,6 @@ class FooStreamBlock(blocks.StreamBlock):
|
|||
|
||||
|
||||
class TestFieldBlock(unittest.TestCase):
|
||||
def test_integerfield_type(self):
|
||||
block = blocks.IntegerBlock()
|
||||
digit = block.value_from_form(1234)
|
||||
|
||||
self.assertEqual(type(digit), int)
|
||||
|
||||
def test_integerfield_render(self):
|
||||
block = blocks.IntegerBlock()
|
||||
digit = block.value_from_form(1234)
|
||||
|
||||
self.assertEqual(digit, 1234)
|
||||
|
||||
def test_integerfield_render_required_error(self):
|
||||
block = blocks.IntegerBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_integerfield_render_max_value_validation(self):
|
||||
block = blocks.IntegerBlock(max_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean(25)
|
||||
|
||||
def test_integerfield_render_min_value_validation(self):
|
||||
block = blocks.IntegerBlock(min_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean(10)
|
||||
|
||||
def test_emailfield_render(self):
|
||||
block = blocks.EmailBlock()
|
||||
email = block.render("example@email.com")
|
||||
|
||||
self.assertEqual(email, "example@email.com")
|
||||
|
||||
def test_emailfield_render_required_error(self):
|
||||
block = blocks.EmailBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_emailfield_format_validation(self):
|
||||
block = blocks.EmailBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("example.email.com")
|
||||
|
||||
def test_charfield_render(self):
|
||||
block = blocks.CharBlock()
|
||||
html = block.render("Hello world!")
|
||||
|
@ -194,6 +147,156 @@ class TestFieldBlock(unittest.TestCase):
|
|||
self.assertIn('animations.js', ''.join(block.all_media().render_js()))
|
||||
|
||||
|
||||
class TestIntegerBlock(unittest.TestCase):
|
||||
def test_type(self):
|
||||
block = blocks.IntegerBlock()
|
||||
digit = block.value_from_form(1234)
|
||||
|
||||
self.assertEqual(type(digit), int)
|
||||
|
||||
def test_render(self):
|
||||
block = blocks.IntegerBlock()
|
||||
digit = block.value_from_form(1234)
|
||||
|
||||
self.assertEqual(digit, 1234)
|
||||
|
||||
def test_render_required_error(self):
|
||||
block = blocks.IntegerBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_render_max_value_validation(self):
|
||||
block = blocks.IntegerBlock(max_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean(25)
|
||||
|
||||
def test_render_min_value_validation(self):
|
||||
block = blocks.IntegerBlock(min_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean(10)
|
||||
|
||||
|
||||
class TestEmailBlock(unittest.TestCase):
|
||||
def test_render(self):
|
||||
block = blocks.EmailBlock()
|
||||
email = block.render("example@email.com")
|
||||
|
||||
self.assertEqual(email, "example@email.com")
|
||||
|
||||
def test_render_required_error(self):
|
||||
block = blocks.EmailBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_format_validation(self):
|
||||
block = blocks.EmailBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("example.email.com")
|
||||
|
||||
|
||||
class TestFloatBlock(TestCase):
|
||||
def test_type(self):
|
||||
block = blocks.FloatBlock()
|
||||
block_val = block.value_from_form(float(1.63))
|
||||
self.assertEqual(type(block_val), float)
|
||||
|
||||
def test_render(self):
|
||||
block = blocks.FloatBlock()
|
||||
test_val = float(1.63)
|
||||
block_val = block.value_from_form(test_val)
|
||||
self.assertEqual(block_val, test_val)
|
||||
|
||||
def test_raises_required_error(self):
|
||||
block = blocks.FloatBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_raises_max_value_validation_error(self):
|
||||
block = blocks.FloatBlock(max_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean('20.01')
|
||||
|
||||
def test_raises_min_value_validation_error(self):
|
||||
block = blocks.FloatBlock(min_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean('19.99')
|
||||
|
||||
|
||||
class TestDecimalBlock(TestCase):
|
||||
def test_type(self):
|
||||
block = blocks.DecimalBlock()
|
||||
block_val = block.value_from_form(Decimal('1.63'))
|
||||
self.assertEqual(type(block_val), Decimal)
|
||||
|
||||
def test_render(self):
|
||||
block = blocks.DecimalBlock()
|
||||
test_val = Decimal(1.63)
|
||||
block_val = block.value_from_form(test_val)
|
||||
|
||||
self.assertEqual(block_val, test_val)
|
||||
|
||||
def test_raises_required_error(self):
|
||||
block = blocks.DecimalBlock()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_raises_max_value_validation_error(self):
|
||||
block = blocks.DecimalBlock(max_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean('20.01')
|
||||
|
||||
def test_raises_min_value_validation_error(self):
|
||||
block = blocks.DecimalBlock(min_value=20)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean('19.99')
|
||||
|
||||
|
||||
class TestRegexBlock(TestCase):
|
||||
|
||||
def test_render(self):
|
||||
block = blocks.RegexBlock(regex=r'^[0-9]{3}$')
|
||||
test_val = '123'
|
||||
block_val = block.value_from_form(test_val)
|
||||
|
||||
self.assertEqual(block_val, test_val)
|
||||
|
||||
def test_raises_required_error(self):
|
||||
block = blocks.RegexBlock(regex=r'^[0-9]{3}$')
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("")
|
||||
|
||||
def test_raises_validation_error(self):
|
||||
block = blocks.RegexBlock(regex=r'^[0-9]{3}$')
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("[/]")
|
||||
|
||||
def test_raises_custom_error_message(self):
|
||||
test_message = 'Not a valid library card number.'
|
||||
block = blocks.RegexBlock(regex=r'^[0-9]{3}$', error_message=test_message)
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
block.clean("[/]")
|
||||
|
||||
html = block.render_form(
|
||||
"[/]",
|
||||
errors=ErrorList([ValidationError(test_message)]))
|
||||
|
||||
self.assertIn(test_message, html)
|
||||
|
||||
|
||||
class TestRichTextBlock(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue