def test_field_from_model_supports_all_types(): from django.db.models import fields not_supported = [] blacklist = { 'AutoField', 'Field', 'BigAutoField', 'BinaryField', 'FilePathField', 'GenericIPAddressField', 'IPAddressField', 'NullBooleanField', 'SlugField', 'DurationField', 'UUIDField' } field_type_names = [x for x in dir(fields) if x.endswith('Field') and x not in blacklist] for name in field_type_names: field_type = getattr(fields, name) try: Field.from_model(model=Foo, model_field=field_type()) except AssertionError: # pragma: no cover not_supported.append(name) assert not_supported == []
def test_email_field(): assert Form(data=Data(foo=' 5 '), fields=[Field.email(name='foo')]).fields[0].errors == { u'Enter a valid email address.' } assert Form(data=Data(foo='*****@*****.**'), fields=[Field.email(name='foo')]).is_valid()
def test_float_field(): assert Form(data=Data(foo=' 7.3 '), fields=[Field.float(name='foo')]).fields[0].parsed_data == 7.3 assert Form(data=Data(foo=' foo '), fields=[Field.float(name='foo')]).fields[0].errors == { "could not convert string to float: foo" }
def test_comma_separated_errors_on_parse(): def raise_always_value_error(string_value, **_): raise ValueError('foo %s!' % string_value) def raise_always_validation_error(string_value, **_): raise ValidationError( ['foo %s!' % string_value, 'bar %s!' % string_value]) assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', parse=raise_always_value_error)) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!' } assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', parse=raise_always_validation_error)) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "5": bar 5!', u'Invalid value "7": foo 7!', u'Invalid value "7": bar 7!' }
def test_integer_field(): assert Form(data=Data(foo=' 7 '), fields=[Field.integer(name='foo')]).fields[0].parsed_data == 7 actual_errors = Form(data=Data(foo=' foo '), fields=[Field.integer(name='foo')]).fields[0].errors assert_one_error_and_matches_reg_exp( actual_errors, "invalid literal for int\(\) with base 10: u?'foo'")
class LoginForm(Form): username = Field() password = Field.password() next = Field.hidden(initial=request.GET.get('next', '/')) def is_valid(self): if not super(LoginForm, self).is_valid(): return False username = self.fields_by_name['username'].value password = self.fields_by_name['password'].value if username and password: user = User.objects.get(username=username) self.extra.user = user if authenticate(request=request, username=username, password=password): return True try: username = User.objects.get(username=username) if b64encode(sha1(password.encode()).digest()).decode( ) == user.password: user.set_password(password) # upgrade password user.save() authenticate(request=request, username=username, password=password) except User.DoesNotExist: pass return False
def test_field_from_model_blank_handling(): from django.db.models import CharField subject = Field.from_model(model=Foo, model_field=CharField(blank=False)) assert True is subject.parse_empty_string_as_none subject = Field.from_model(model=Foo, model_field=CharField(blank=True)) assert False is subject.parse_empty_string_as_none
class ChangeSubscriptionForm(Form): choices = Field.radio(choices=['Subscribe', 'Unsubscribe'], initial='Subscribe') passive = Field.boolean( display_name='Show only when unread', initial=subscription and subscription.subscription_type == 'passive') identifier = Field.hidden(initial=identifier_)
class ResetPasswordForm(Form): reset_code = Field( is_valid=lambda parsed_data, **_: (parsed_data is not None, 'Invalid reset password code'), parse=parse) new_password = Field.password() confirm_password = Field.password( is_valid=lambda parsed_data, **_: (parsed_data == request.POST.get( 'new_password'), 'Passwords do not match'))
def test_show(): assert list( Form(data=Data(), fields=[Field(name='foo', show=False)]).fields_by_name.keys()) == [] assert list( Form(data=Data(), fields=[Field(name='foo', show=lambda form, field: False) ]).fields_by_name.keys()) == []
class EditForm(Form): assetNumber = Field.text() assetSerial = Field.text() assetType = Field.choices(attr=None, choices=Asset.objects.values('assetTypes__type')) model_number = Field.text() #location = Field.multi_choice(attr=None, choices=Location.objects.values_list('floor')) floor = Field.multi_choice_queryset( attr=None, choices=Asset.objects.only('locationInfo__floor'))
def test_comma_separated_errors_on_validation(): assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', is_valid=lambda parsed_data, **_: (False, 'foo %s!' % parsed_data))) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!' }
def test_phone_field(): assert Form( data=Data(foo=' asdasd '), fields=[Field.phone_number(name='foo')] ).fields[0].errors == { u'Please use format +<country code> (XX) XX XX. Example of US number: +1 (212) 123 4567 or +1 212 123 4567' } assert Form(data=Data(foo='+1 (212) 123 4567'), fields=[Field.phone_number(name='foo')]).is_valid() assert Form(data=Data(foo='+46 70 123 123'), fields=[Field.phone_number(name='foo')]).is_valid()
def test_field_from_model_many_to_many(): Foo.objects.create(foo=2) Foo.objects.create(foo=3) Foo.objects.create(foo=5) choices = Field.from_model(FieldFromModelManyToManyTest, 'foo_many_to_many').choices assert isinstance(choices, QuerySet) assert set(choices) == set(Foo.objects.all())
def test_comma_separated_errors_on_validation(): assert Form( data=dict(foo='5, 7'), fields=[Field.comma_separated(Field(name='foo', is_valid=lambda parsed_data, **_: (False, 'foo %s!' % parsed_data)))]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!', }
def test_render_custom(): sentinel = '!!custom!!' assert sentinel in Form(fields=[ Field(name='foo', initial='not sentinel value', render_value=lambda form, field, value: sentinel), ]).table()
def test_boolean_initial_true(): fields = [ Field.boolean(name='foo', initial=True), Field(name='bar', required=False) ] form = Form(data=Data(), fields=fields) assert form.fields_by_name['foo'].value is True # If there are arguments, but not for key foo it means checkbox for foo has been unchecked. # Field foo should therefore be false. form = Form(data=Data(bar='baz', **{'-': '-'}), fields=fields) assert form.fields_by_name['foo'].value is False form = Form(data=Data(foo='on', bar='baz', **{'-': '-'}), fields=fields) assert form.fields_by_name['foo'].value is True
def test_render_datetime_iso(): table = Form(fields=[ Field.datetime(name='foo', initial=datetime(2001, 2, 3, 12, 13, 14, 7777)) ]).table() assert '2001-02-03 12:13:14' in table assert '7777' not in table
def test_field_from_model_foreign_key(): Foo.objects.create(foo=2) Foo.objects.create(foo=3) Foo.objects.create(foo=5) choices = Field.from_model(FieldFromModelForeignKeyTest, 'foo_fk').choices assert isinstance(choices, QuerySet) assert set(choices) == set(Foo.objects.all())
def test_render_template_string(): assert Form(data=Data(foo='7'), fields=[ Field(name='foo', template=None, template_string='{{ field.value }} {{ form.style }}') ]).compact() == '7 compact\n' + AVOID_EMPTY_FORM
def test_render_datetime_iso(): table = Form(fields=[ Field.datetime( name='foo', initial=datetime(2001, 2, 3, 12, 13, 14, 7777)) ]).table() assert '2001-02-03 12:13:14' in table assert '7777' not in table
class MyTestForm(Form): party = Field.choice(choices=['ABC'], required=False) username = Field(is_valid=lambda form, field, parsed_data: ( parsed_data.startswith(form.fields_by_name['party'].parsed_data.lower( ) + '_') if parsed_data is not None else None, 'Username must begin with "%s_"' % form.fields_by_name['party'].parsed_data)) joined = Field.datetime(attr='contact__joined') a_date = Field.date() a_time = Field.time() staff = Field.boolean() admin = Field.boolean() manages = Field.multi_choice(choices=['DEF', 'KTH', 'LIU'], required=False) not_editable = Field.text(initial='Some non-editable text', editable=False)
def test_radio(): choices = [ 'a', 'b', 'c', ] soup = BeautifulSoup(Form(data=Data(foo='a'), fields=[Field.radio(name='foo', choices=choices)]).validate().table()) assert len(soup.find_all('input')) == len(choices) + 1 # +1 for AVOID_EMPTY_FORM assert [x.attrs['value'] for x in soup.find_all('input') if 'checked' in x.attrs] == ['a']
def test_comma_separated_errors_on_parse(): def raise_always_value_error(string_value, **_): raise ValueError('foo %s!' % string_value) def raise_always_validation_error(string_value, **_): raise ValidationError(['foo %s!' % string_value, 'bar %s!' % string_value]) assert Form( data=Data(foo='5, 7'), fields=[Field.comma_separated(Field(name='foo', parse=raise_always_value_error))]).validate().fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!'} assert Form( data=Data(foo='5, 7'), fields=[Field.comma_separated(Field(name='foo', parse=raise_always_validation_error))]).validate().fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "5": bar 5!', u'Invalid value "7": foo 7!', u'Invalid value "7": bar 7!'}
def test_field_from_model_supports_all_types(): from django.db.models import fields not_supported = [] blacklist = { 'AutoField', 'Field', 'BigAutoField', 'BinaryField', 'FilePathField', 'GenericIPAddressField', 'IPAddressField', 'NullBooleanField', 'SlugField', 'DurationField', 'UUIDField' } field_type_names = [ x for x in dir(fields) if x.endswith('Field') and x not in blacklist ] for name in field_type_names: field_type = getattr(fields, name) try: Field.from_model(model=Foo, model_field=field_type()) except AssertionError: # pragma: no cover not_supported.append(name) assert not_supported == []
def test_boolean_initial_true(): fields = [Field.boolean(name='foo', initial=True), Field(name='bar', required=False)] form = Form(data=Data(), fields=fields).validate() assert form.fields_by_name['foo'].value is True # If there are arguments, but not for key foo it means checkbox for foo has been unchecked. # Field foo should therefore be false. form = Form(data=Data(bar='baz'), fields=fields).validate() assert form.fields_by_name['foo'].value is False form = Form(data=Data(foo='on', bar='baz'), fields=fields).validate() assert form.fields_by_name['foo'].value is True
def test_radio(): choices = [ 'a', 'b', 'c', ] soup = BeautifulSoup( Form(data=Data(foo='a'), fields=[Field.radio(name='foo', choices=choices)]).table()) assert len( soup.find_all('input')) == len(choices) + 1 # +1 for AVOID_EMPTY_FORM assert [ x.attrs['value'] for x in soup.find_all('input') if 'checked' in x.attrs ] == ['a']
def tri_form_example4(request, pk): def on_save(instance, form, **_): if request.user.contact.is_auditor and form.fields_by_name.audit_complete.value: instance.last_audit = datetime.now() instance.auditor = request.user instance.save() return edit_object( request=request, instance=Room.objects.get(pk=pk), on_save=on_save, form__extra_fields=[ Field.boolean( name='audit_complete', attr=None, # don't write "audit_complete" to the Room object show=request.user.contact.is_auditor, ), Field.heading( name='audit', after='description', show=request.user.contact.is_auditor or request.user.is_staff, ), ], form__field=dict( auditor_notes__show=request.user.is_staff or request.user.contact.is_auditor, auditor_notes__editable=request.user.contact.is_auditor, auditor__editable=False, auditor__show=request.user.is_staff, last_audit__editable=False, last_audit__show=request.user.is_staff, last_audit__container__attrs__class__audit=True, auditor__container__attrs__class__audit=True, auditor_notes__container__attrs__class__audit=True, ), )
def test_render_table(): form = Form(data=Data(foo='!!!7!!!'), fields=[ Field( name='foo', input_container_css_classes={'###5###'}, label_container_css_classes={'$$$11$$$'}, help_text='^^^13^^^', label='***17***', ) ]) table = form.table() assert '!!!7!!!' in table assert '###5###' in table assert '$$$11$$$' in table assert '^^^13^^^' in table assert '***17***' in table assert '<tr' in table # Assert that table is the default assert table == "%s" % form
def tri_form_example3(request, pk): def on_save(instance, form, **_): if request.user.is_staff and form.fields_by_name.audit_complete.value: instance.last_audit = datetime.now() instance.auditor = request.user instance.save() return edit_object( request=request, instance=Room.objects.get(pk=pk), on_save=on_save, form__exclude=['auditor', 'last_audit'], form__extra_fields=[ Field.boolean( name='audit_complete', attr=None, # don't write "audit_complete" to the Room object show=request.user.is_staff, ), ], form__field__auditor_notes__show=request.user.is_staff, )
def test_hidden(): soup = BeautifulSoup(Form(data=Data(foo='1'), fields=[Field.hidden(name='foo')]).validate().table()) assert [(x.attrs['type'], x.attrs['value']) for x in soup.find_all('input')] == [('hidden', '1'), ('hidden', '-')]
def test_password(): assert ' type="password" ' in Form(data=Data(foo='1'), fields=[Field.password(name='foo')]).validate().table()
def test_heading(): assert '<th colspan="2">#foo#</th>' in Form(data={}, fields=[Field.heading(label='#foo#')]).validate().table()
def test_text_fields(): assert '<input type="text" ' in Form(data={}, fields=[Field.text(name='foo')]).compact() assert '<textarea' in Form(data={}, fields=[Field.textarea(name='foo')]).compact()
def test_register_field_factory(): register_field_factory(FooField, lambda **kwargs: 7) assert Field.from_model(RegisterFieldFactoryTest, 'foo') == 7
def test_multi_select_with_one_value_only(): assert ['a'] == Form(data=Data(foo=['a']), fields=[Field.multi_choice(name='foo', choices=['a', 'b'])]).validate().fields[0].value_list
def test_multi_email(): assert Form(data=Data(foo='[email protected], [email protected]'), fields=[Field.comma_separated(Field.email(name='foo'))]).is_valid()
def test_choices_from_query_set(): user = User.objects.create(username='******') assert [x.pk for x in Form(fields=[Field.multi_choice_queryset(name='foo', model=User, choices=User.objects.all())]).validate().fields[0].choices] == [user.pk]
def test_float_field(): assert Form(data=Data(foo=' 7.3 '), fields=[Field.float(name='foo')]).validate().fields[0].parsed_data == 7.3 assert Form(data=Data(foo=' foo '), fields=[Field.float(name='foo')]).validate().fields[0].errors == {"could not convert string to float: foo"}
def test_email_field(): assert Form(data=Data(foo=' 5 '), fields=[Field.email(name='foo')]).validate().fields[0].errors == {u'Enter a valid email address.'} assert Form(data=Data(foo='*****@*****.**'), fields=[Field.email(name='foo')]).is_valid()
def test_integer_field(): assert Form(data=Data(foo=' 7 '), fields=[Field.integer(name='foo')]).validate().fields[0].parsed_data == 7 assert Form(data=Data(foo=' foo '), fields=[Field.integer(name='foo')]).validate().fields[0].errors == {"invalid literal for int() with base 10: 'foo'"}
def test_info(): form = Form(data={}, fields=[Field.info(value='#foo#')]) assert form.is_valid() assert '#foo#' in form.table()
class FooForm(Form): foo = Field(required=True) bar = Field(required=True) baz = Field.boolean(initial=True)
def test_multi_choice(): soup = BeautifulSoup(Form(data=Data(foo=['0']), fields=[Field.multi_choice(name='foo', choices=['a'])]).validate().table()) assert [x.attrs['multiple'] for x in soup.find_all('select')] == ['']
class FooForm(Form): foo = Field.file(required=False)
def test_help_text_from_model(): assert Form(data=Data(foo='1'), fields=[Field.from_model(model=Foo, field_name='foo')], model=Foo).validate().fields[0].help_text == 'foo_help_text'
def test_phone_field(): assert Form(data=Data(foo=' asdasd '), fields=[Field.phone_number(name='foo')]).validate().fields[0].errors == {u'Please use format +<country code> (XX) XX XX. Example of US number: +1 (212) 123 4567 or +1 212 123 4567'} assert Form(data=Data(foo='+1 (212) 123 4567'), fields=[Field.phone_number(name='foo')]).is_valid() assert Form(data=Data(foo='+46 70 123 123'), fields=[Field.phone_number(name='foo')]).is_valid()
def test_datetime_not_required(): assert Form(fields=[ Field.datetime( required=False, name='foo') ], data={'foo': ''}).is_valid()
class ForgotPasswordForm(Form): username_or_email = Field( is_valid=lambda parsed_data, **_: (parsed_data is not None, 'Unknown username or email'), parse=parse)
def test_render_datetime_iso(): assert '2001-02-03 12:13:14' in Form(fields=[ Field.datetime( name='foo', initial=datetime(2001, 2, 3, 12, 13, 14)) ]).validate().table()
class MyForm(Form): foo = Field() bar = Field()
class MyForm(Form): foo = Field(is_valid=lambda **_: (False, 'field error'))
def test_integer_field(): assert Form(data=dict(foo=' 7 '), fields=[Field.integer(name='foo')]).fields[0].parsed_data == 7 actual_errors = Form(data=dict(foo=' foo '), fields=[Field.integer(name='foo')]).fields[0].errors assert_one_error_and_matches_reg_exp(actual_errors, "invalid literal for int\(\) with base 10: u?'foo'")
class MyForm(Form): username = Field.choice_queryset(choices=User.objects.all(), extra__endpoint_attr='username')
def test_json_parsing(): # NOTE: Parsing json input requires that any numbers that come in must avoid the string strip f = Form(data={'foo': 1}, fields=[Field.integer(name='foo', strip_input=False)]) assert f.is_valid() assert f.fields_by_name['foo'].value == 1