Skip to content
  • 3 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Showing with 124 additions and 6 deletions.
  1. +42 −2 wtfpeewee/fields.py
  2. +26 −4 wtfpeewee/orm.py
  3. +56 −0 wtfpeewee/tests.py
View
44 wtfpeewee/fields.py
@@ -6,16 +6,56 @@
import warnings
from wtforms import widgets
-from wtforms.fields import SelectFieldBase, HiddenField
+from wtforms.fields import SelectField, SelectFieldBase, HiddenField
from wtforms.validators import ValidationError
__all__ = (
'ModelSelectField', 'ModelSelectMultipleField', 'ModelHiddenField',
- 'SelectQueryField', 'SelectMultipleQueryField', 'HiddenQueryField'
+ 'SelectQueryField', 'SelectMultipleQueryField', 'HiddenQueryField',
+ 'SelectChoicesField',
)
+class SelectChoicesField(SelectField):
+ # all of this exists so i can get proper handling of None
+ def __init__(self, label=None, validators=None, coerce=unicode, choices=None, allow_blank=False, blank_text=u'', **kwargs):
+ super(SelectChoicesField, self).__init__(label, validators, coerce, choices, **kwargs)
+ self.allow_blank = allow_blank
+ self.blank_text = blank_text or '----------------'
+
+ def iter_choices(self):
+ if self.allow_blank:
+ yield (u'__None', self.blank_text, self.data is None)
+
+ for value, label in self.choices:
+ yield (value, label, self.coerce(value) == self.data)
+
+ def process_data(self, value):
+ if value is None:
+ self.data = None
+ else:
+ try:
+ self.data = self.coerce(value)
+ except (ValueError, TypeError):
+ self.data = None
+
+ def process_formdata(self, valuelist):
+ if valuelist:
+ if valuelist[0] == '__None':
+ self.data = None
+ else:
+ try:
+ self.data = self.coerce(valuelist[0])
+ except ValueError:
+ raise ValueError(self.gettext(u'Invalid Choice: could not coerce'))
+
+ def pre_validate(self, form):
+ if self.allow_blank and self.data is None:
+ return
+ super(SelectChoicesField, self).pre_validate(form)
+
+
class SelectQueryField(SelectFieldBase):
"""
Given a SelectQuery either at initialization or inside a view, will display a
View
30 wtfpeewee/orm.py
@@ -2,10 +2,11 @@
Tools for generating forms based on Peewee models
(cribbed from wtforms.ext.django)
"""
+from decimal import Decimal
from wtforms import fields as f
from wtforms import Form
from wtforms import validators
-from wtfpeewee.fields import ModelSelectField
+from wtfpeewee.fields import ModelSelectField, SelectChoicesField
from peewee import PrimaryKeyField, IntegerField, FloatField, DateTimeField,\
BooleanField, CharField, TextField, ForeignKeyField, DecimalField, DateField,\
@@ -35,19 +36,33 @@ class ModelConverter(object):
CharField: f.TextField,
TextField: f.TextAreaField,
}
+ coerce_defaults = {
+ IntegerField: int,
+ FloatField: float,
+ CharField: unicode,
+ TextField: unicode,
+ }
required = (DateTimeField, CharField, TextField, ForeignKeyField,)
- def __init__(self, additional=None):
+ def __init__(self, additional=None, additional_coerce=None):
self.converters = {
ForeignKeyField: self.handle_foreign_key,
}
if additional:
self.converters.update(additional)
+
+ self.coerce_settings = dict(self.coerce_defaults)
+ if additional_coerce:
+ self.coerce_settings.update(additional_coerce)
def handle_foreign_key(self, model, field, **kwargs):
if field.null:
kwargs['allow_blank'] = True
- return field.name, ModelSelectField(model=field.to, **kwargs)
+ if field.choices is not None:
+ field_obj = SelectQueryField(query=field.choices, **kwargs)
+ else:
+ field_obj = ModelSelectField(model=field.to, **kwargs)
+ return field.name, field_obj
def convert(self, model, field, field_args):
kwargs = dict(
@@ -61,7 +76,6 @@ def convert(self, model, field, field_args):
kwargs.update(field_args)
if field.null:
- kwargs['validators'].append(validators.Optional())
kwargs['filters'].append(handle_null_filter)
else:
if isinstance(field, self.required):
@@ -72,6 +86,14 @@ def convert(self, model, field, field_args):
if field_class in self.converters:
return self.converters[field_class](model, field, **kwargs)
elif field_class in self.defaults:
+ if field.choices or 'choices' in kwargs:
+ choices = kwargs.pop('choices', field.choices)
+ if field_class in self.coerce_settings or 'coerce' in kwargs:
+ coerce_fn = kwargs.pop('coerce', self.coerce_settings[field_class])
+ allow_blank = kwargs.pop('allow_blank', field.null)
+ kwargs.update(dict(choices=choices, coerce=coerce_fn, allow_blank=allow_blank))
+ return field.name, SelectChoicesField(**kwargs)
+
return field.name, self.defaults[field_class](**kwargs)
View
56 wtfpeewee/tests.py
@@ -38,9 +38,17 @@ class NullFieldsModel(TestModel):
b = BooleanField(null=True)
+class ChoicesModel(TestModel):
+ gender = CharField(choices=(('m', 'Male'), ('f', 'Female')))
+ status = IntegerField(choices=((1, 'One'), (2, 'Two')), null=True)
+ salutation = CharField(null=True)
+ true_or_false = BooleanField(choices=((True, 't'), (False, 'f')))
+
+
BlogForm = model_form(Blog)
EntryForm = model_form(Entry)
NullFieldsModelForm = model_form(NullFieldsModel)
+ChoicesForm = model_form(ChoicesModel, field_args={'salutation': {'choices': (('mr', 'Mr.'), ('mrs', 'Mrs.'))}})
class FakePost(dict):
def getlist(self, key):
@@ -67,6 +75,54 @@ def setUp(self):
self.entry_a2 = Entry.create(blog=self.blog_a, title='a2', content='a2 content', pub_date=datetime.datetime(2011, 1, 2))
self.entry_b1 = Entry.create(blog=self.blog_b, title='b1', content='b1 content', pub_date=datetime.datetime(2011, 1, 1))
+ def test_choices(self):
+ form = ChoicesForm()
+ self.assertTrue(isinstance(form.gender, SelectChoicesField))
+ self.assertTrue(isinstance(form.status, SelectChoicesField))
+ self.assertTrue(isinstance(form.salutation, SelectChoicesField))
+ self.assertTrue(isinstance(form.true_or_false, wtfields.BooleanField))
+
+ self.assertEqual(list(form.gender.iter_choices()), [
+ ('m', 'Male', False), ('f', 'Female', False)
+ ])
+ self.assertEqual(list(form.status.iter_choices()), [
+ ('__None', '----------------', True), (1, 'One', False), (2, 'Two', False)
+ ])
+ self.assertEqual(list(form.salutation.iter_choices()), [
+ ('__None', '----------------', True), ('mr', 'Mr.', False), ('mrs', 'Mrs.', False),
+ ])
+
+ choices_obj = ChoicesModel(gender='m', status=2, salutation=None)
+ form = ChoicesForm(obj=choices_obj)
+ self.assertEqual(form.data, {'gender': 'm', 'status': 2, 'salutation': None, 'true_or_false': False})
+ self.assertTrue(form.validate())
+
+ choices_obj = ChoicesModel(gender='f', status=1, salutation='mrs', true_or_false=True)
+ form = ChoicesForm(obj=choices_obj)
+ self.assertEqual(form.data, {'gender': 'f', 'status': 1, 'salutation': 'mrs', 'true_or_false': True})
+ self.assertTrue(form.validate())
+
+ choices_obj.gender = 'x'
+ form = ChoicesForm(obj=choices_obj)
+ self.assertFalse(form.validate())
+ self.assertEqual(form.errors, {'gender': ['Not a valid choice']})
+
+ choices_obj.gender = 'm'
+ choices_obj.status = '1'
+ form = ChoicesForm(obj=choices_obj)
+ self.assertEqual(form.status.data, 1)
+ self.assertTrue(form.validate())
+
+ choices_obj.status = '3'
+ form = ChoicesForm(obj=choices_obj)
+
+ self.assertFalse(form.validate())
+
+ choices_obj.status = None
+ form = ChoicesForm(obj=choices_obj)
+ self.assertEqual(form.status.data, None)
+ self.assertTrue(form.validate())
+
def test_blog_form(self):
form = BlogForm()
self.assertEqual(form._fields.keys(), ['title'])

No commit comments for this range

Something went wrong with that request. Please try again.