From 53cf639e047e75167ff937afc984869356747090 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Wed, 22 Jan 2020 10:34:03 +1100 Subject: [PATCH 1/4] Allow customizing blank value in QuerySelectField --- wtforms_sqlalchemy/fields.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wtforms_sqlalchemy/fields.py b/wtforms_sqlalchemy/fields.py index da5cb47..4ebc888 100644 --- a/wtforms_sqlalchemy/fields.py +++ b/wtforms_sqlalchemy/fields.py @@ -57,7 +57,7 @@ class QuerySelectField(SelectFieldBase): def __init__(self, label=None, validators=None, query_factory=None, get_pk=None, get_label=None, allow_blank=False, - blank_text='', **kwargs): + blank_value='__None', blank_text='', **kwargs): super(QuerySelectField, self).__init__(label, validators, **kwargs) self.query_factory = query_factory @@ -76,6 +76,7 @@ def __init__(self, label=None, validators=None, query_factory=None, self.get_label = get_label self.allow_blank = allow_blank + self.blank_value = blank_value self.blank_text = blank_text self.query = None self._object_list = None @@ -106,14 +107,14 @@ def _get_object_list(self): def iter_choices(self): if self.allow_blank: - yield ('__None', self.blank_text, self.data is None) + yield (self.blank_value, self.blank_text, self.data is None) for pk, obj in self._get_object_list(): yield (pk, self.get_label(obj), obj == self.data) def process_formdata(self, valuelist): if valuelist: - if self.allow_blank and valuelist[0] == '__None': + if self.allow_blank and valuelist[0] == self.blank_value: self.data = None else: self._data = None From 6a069bcae2fec5443862400810b62a2d8a0c7f33 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Wed, 22 Jan 2020 10:39:24 +1100 Subject: [PATCH 2/4] Show blank option in QuerySelectField if nothing is selected Otherwise the first option is effectively the default. If users don't change anything, or don't notice the select, then the first option will be automatically selected. --- tests/tests.py | 6 +++--- wtforms_sqlalchemy/fields.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index 1e588fa..e1cc643 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -105,7 +105,7 @@ class F(Form): .filter(self.Test.id == 1, self.Test.id != 1) .all() ) - self.assertEqual(form.a(), []) + self.assertEqual(form.a(), [('__None', '', True)]) def test_with_query_factory(self): @@ -118,7 +118,7 @@ class F(Form): form = F() self.assertEqual(form.a.data, None) - self.assertEqual(form.a(), [('1', 'apple', False), ('2', 'banana', False)]) + self.assertEqual(form.a(), [('__None', '', True), ('1', 'apple', False), ('2', 'banana', False)]) self.assertEqual(form.b.data, None) self.assertEqual(form.b(), [('__None', '', True), ('hello1', 'apple', False), ('hello2', 'banana', False)]) self.assertFalse(form.validate()) @@ -152,7 +152,7 @@ class F(Form): .filter(self.Test.id == 1, self.Test.id != 1) .all() ) - self.assertEqual(form.a(), []) + self.assertEqual(form.a(), [('__None', '', True)]) class QuerySelectMultipleFieldTest(TestBase): diff --git a/wtforms_sqlalchemy/fields.py b/wtforms_sqlalchemy/fields.py index 4ebc888..72517ec 100644 --- a/wtforms_sqlalchemy/fields.py +++ b/wtforms_sqlalchemy/fields.py @@ -106,7 +106,7 @@ def _get_object_list(self): return self._object_list def iter_choices(self): - if self.allow_blank: + if self.allow_blank or self.data is None: yield (self.blank_value, self.blank_text, self.data is None) for pk, obj in self._get_object_list(): From 1cc3679cd65f3c60c789133b9ce3f56a461983d5 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Wed, 22 Jan 2020 10:42:47 +1100 Subject: [PATCH 3/4] Set default "Select..." text for QuerySelectField.blank_label --- tests/tests.py | 10 +++++----- wtforms_sqlalchemy/fields.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/tests.py b/tests/tests.py index e1cc643..45e9fb8 100755 --- a/tests/tests.py +++ b/tests/tests.py @@ -105,7 +105,7 @@ class F(Form): .filter(self.Test.id == 1, self.Test.id != 1) .all() ) - self.assertEqual(form.a(), [('__None', '', True)]) + self.assertEqual(form.a(), [('__None', 'Select...', True)]) def test_with_query_factory(self): @@ -118,16 +118,16 @@ class F(Form): form = F() self.assertEqual(form.a.data, None) - self.assertEqual(form.a(), [('__None', '', True), ('1', 'apple', False), ('2', 'banana', False)]) + self.assertEqual(form.a(), [('__None', 'Select...', True), ('1', 'apple', False), ('2', 'banana', False)]) self.assertEqual(form.b.data, None) - self.assertEqual(form.b(), [('__None', '', True), ('hello1', 'apple', False), ('hello2', 'banana', False)]) + self.assertEqual(form.b(), [('__None', 'Select...', True), ('hello1', 'apple', False), ('hello2', 'banana', False)]) self.assertFalse(form.validate()) form = F(DummyPostData(a=['1'], b=['hello2'])) self.assertEqual(form.a.data.id, 1) self.assertEqual(form.a(), [('1', 'apple', True), ('2', 'banana', False)]) self.assertEqual(form.b.data.baz, 'banana') - self.assertEqual(form.b(), [('__None', '', False), ('hello1', 'apple', False), ('hello2', 'banana', True)]) + self.assertEqual(form.b(), [('__None', 'Select...', False), ('hello1', 'apple', False), ('hello2', 'banana', True)]) self.assertTrue(form.validate()) # Make sure the query is cached @@ -152,7 +152,7 @@ class F(Form): .filter(self.Test.id == 1, self.Test.id != 1) .all() ) - self.assertEqual(form.a(), [('__None', '', True)]) + self.assertEqual(form.a(), [('__None', 'Select...', True)]) class QuerySelectMultipleFieldTest(TestBase): diff --git a/wtforms_sqlalchemy/fields.py b/wtforms_sqlalchemy/fields.py index 72517ec..dd7a347 100644 --- a/wtforms_sqlalchemy/fields.py +++ b/wtforms_sqlalchemy/fields.py @@ -57,7 +57,7 @@ class QuerySelectField(SelectFieldBase): def __init__(self, label=None, validators=None, query_factory=None, get_pk=None, get_label=None, allow_blank=False, - blank_value='__None', blank_text='', **kwargs): + blank_value='__None', blank_text='Select...', **kwargs): super(QuerySelectField, self).__init__(label, validators, **kwargs) self.query_factory = query_factory @@ -107,7 +107,7 @@ def _get_object_list(self): def iter_choices(self): if self.allow_blank or self.data is None: - yield (self.blank_value, self.blank_text, self.data is None) + yield (self.blank_value, self.gettext(self.blank_text), self.data is None) for pk, obj in self._get_object_list(): yield (pk, self.get_label(obj), obj == self.data) From 05d133c47376af8edb290c565774e45625dd478b Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Fri, 31 Jan 2020 11:52:09 +1100 Subject: [PATCH 4/4] Better error messages with blank QuerySelectFields --- wtforms_sqlalchemy/fields.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wtforms_sqlalchemy/fields.py b/wtforms_sqlalchemy/fields.py index dd7a347..d509db5 100644 --- a/wtforms_sqlalchemy/fields.py +++ b/wtforms_sqlalchemy/fields.py @@ -6,7 +6,7 @@ import operator from wtforms import widgets -from wtforms.compat import text_type, string_types +from wtforms.compat import string_types, text_type from wtforms.fields import SelectFieldBase from wtforms.validators import ValidationError @@ -128,8 +128,10 @@ def pre_validate(self, form): break else: raise ValidationError(self.gettext('Not a valid choice')) - elif self._formdata or not self.allow_blank: + elif self._formdata is not None: raise ValidationError(self.gettext('Not a valid choice')) + elif not self.allow_blank: + raise ValidationError(self.gettext('This field is required')) class QuerySelectMultipleField(QuerySelectField):