# -*- coding: utf-8 -*-
"""
some utils around newforms
~~~~~~~~~~~~~~~~~~~~~~~~~~
Last commit info:
~~~~~~~~~~~~~~~~~
$LastChangedDate: 2009-04-17 10:07:35 +0100 (Fr, 17 Apr 2009) $
$Rev: 1900 $
$Author: JensDiemer $
:copyleft: 2008 by the PyLucid team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""
import unittest
from django import forms
from django.forms import ValidationError
from django.utils.encoding import smart_unicode
def setup_help_text(form):
"""
Append on every help_text the default information (The initial value)
"""
for field_name, field in form.base_fields.iteritems():
help_text = unicode(field.help_text) # translate gettext_lazy
if u"(default: '" in help_text:
# The default information was inserted in the past
return
field.help_text = "%s (default: '%s')" % (
field.help_text, field.initial
)
def get_init_dict(form):
"""
Returns a dict with all initial values from a newforms class.
"""
init_dict = {}
for field_name, field in form.base_fields.iteritems():
initial = field.initial
# if initial == None:
# msg = (
# "The preferences model attribute '%s' has no initial value!"
# ) % field_name
# raise NoInitialError(msg)
init_dict[field_name] = initial
return init_dict
class NoInitialError(Exception):
"""
All preferences newform attributes must habe a initial value.
"""
pass
class ChoiceField2(forms.ChoiceField):
"""
Works like a ChoiceField, but accepts a list of items. The list are
converted to a tuple fpr rendering.
Returns the value and not the key in clean().
>>> f = ChoiceField2(choices=["A","B","C"])
>>> f.choices
[('0', u'A'), ('1', u'B'), ('2', u'C')]
>>> f.clean('1')
u'B'
"""
def __init__(self, *args, **kwargs):
choices = kwargs.pop("choices")
kwargs["choices"] = self.choices = [
(str(no), smart_unicode(value)) for no, value in enumerate(choices)
]
super(ChoiceField2, self).__init__(*args, **kwargs)
def clean(self, value):
"""
Validates that the input and returns the choiced value.
"""
key = super(ChoiceField2, self).clean(value)
choices_dict = dict(self.choices)
return choices_dict[key]
class StripedCharField(forms.CharField):
"""
Same as forms.CharField but stripes the output.
>>> f = StripedCharField()
>>> f.clean('\\n\\n[\\nTEST\\n]\\n\\n')
u'[\\nTEST\\n]'
"""
def clean(self, value):
value = super(StripedCharField, self).clean(value)
return value.strip()
class ListCharField(forms.CharField):
"""
Items seperated by spaces or other characters.
If the initial is a list/tuple, it would be joined with the seperator.
>>> f = ListCharField()
>>> f.clean(' one two tree')
[u'one', u'two', u'tree']
>>> f = ListCharField(seperator="\\n")
>>> f.clean('one\\ntwo\\n\\ntree\\n\\n')
[u'one', u'two', u'tree']
"""
def __init__(self, seperator=" ", *args, **kwargs):
self.seperator = seperator
if "initial" in kwargs:
initial = kwargs["initial"]
if isinstance(initial, (list, tuple)):
kwargs["initial"] = self.seperator.join(initial)
super(ListCharField, self).__init__(*args, **kwargs)
def clean(self, value):
raw_value = super(ListCharField, self).clean(value)
value = raw_value.strip()
items = [i.strip() for i in value.split(self.seperator)]
items = [i for i in items if i] # eliminate empty items
return items
class ListCharFieldTest(unittest.TestCase):
def test(self):
""" Test if a give list would be joined with the seperator"""
class TestForm(forms.Form):
foo = ListCharField(
seperator="\n", initial=[u'one', u'two', u'tree']
)
f = TestForm()
self.failUnlessEqual(
f.as_p(),
'<p><label for="id_foo">Foo:</label> '
'<input type="text" name="foo" value="one\ntwo\ntree" id="id_foo" />'
'</p>'
)
class InternalURLField(forms.CharField):
"""
Uses e.g. for back urls via a http GET parameter
validates the URL and check if is't a internal url and not
a external.
>>> f = InternalURLField()
>>> f.clean('/a/foobar/url/')
u'/a/foobar/url/'
>>> f.clean('http://eval.domain.tld')
Traceback (most recent call last):
...
ValidationError: [u'Open redirect found.']
>>> f = InternalURLField(must_start_with="/_command/")
>>> f.clean('/_command/a/foobar/url/')
u'/_command/a/foobar/url/'
>>> f.clean('/a/wrong/url/')
Traceback (most recent call last):
...
ValidationError: [u'Open redirect found.']
"""
default_error_message = "Open redirect found."
def __init__(self, must_start_with=None, *args, **kwargs):
self.must_start_with = must_start_with
super(InternalURLField, self).__init__(*args, **kwargs)
def clean(self, value):
value = super(InternalURLField, self).clean(value)
if "://" in value:
raise ValidationError(self.default_error_message)
if self.must_start_with and not value.startswith(self.must_start_with):
raise ValidationError(self.default_error_message)
return value
class ModelForm2(forms.ModelForm):
"""
A model form witch don't validate unique fields.
This ModelForm is only for generating the forms and not for create/update
any database data. So a field unique Test would like generate Errors like:
User with this Username already exists.
see also:
http://www.jensdiemer.de/_command/118/blog/detail/30/ (de)
http://www.python-forum.de/topic-16000.html (de)
"""
def validate_unique(self):
pass
if __name__ == "__main__":
import doctest
doctest.testmod(
# verbose=True
verbose=False
)
print "DocTest end."
unittest.main()
|