On 12/17/06, Adrian Holovaty <[EMAIL PROTECTED]> wrote: > > On 12/16/06, Honza Král <[EMAIL PROTECTED]> wrote: > > there are a few things I would like to see in there (or where > > appropriate) and don't know if somebody is already working on it (or > > other things that would clash with this effort), or if I should give > > it a try. > > Hi Honza, > > Thanks for bringing this up, and see my comments below -- > > > - specifying a widget class when defining a model field (perhaps add a > > keyword param form_widget=DefaultWidget to > > django.db.models.field.Field.__init__() ? ) > > Yes, there should be a way to specify the widget for a field in the > model. The question is, should it be specified as a keyword argument > to the field declaration, or should it be passed in the "class Admin"? > The advantage of the second approach is that it's nicely > compartmentalized, but the advantage of the first is that it's more > compact and also would apply to non-admin forms (like the one you get > for form_for_model). > > > - allowing default to be pre-filled in a field ( I am not sure, if > > this is even useful, or if people will use it, what do you think? ) > > I think adding a "default" parameter to newforms Field classes would > be a nice addition.
I did this one - see the attached patch field_default.patch (all tests passed)
current behaviour may seem sort of strange, but its the best I could
come up with:
In [2]: from django import newforms as forms
In [3]: class MyForm( forms.Form ):
...: test_field = forms.CharField( max_length=20,
required=False, default=u'DEFAULT')
...:
In [4]: form = M
MemoryError MyForm
In [4]: form = MyForm(None)
In [5]: form.as_p()
Out[5]: u'<p><label for="id_test_field">Test field:</label> <input
id="id_test_field" type="text" name="test_field" value="DEFAULT"
maxlength="20" /></p>'
In [6]: form = MyForm({})
In [7]: form.is_valid()
Out[7]: True
In [8]: form.as_p()
Out[8]: u'<p><label for="id_test_field">Test field:</label> <input
id="id_test_field" type="text" name="test_field" value="DEFAULT"
maxlength="20" /></p>'
In [9]: form = MyForm({ 'test_field' : u''})
In [10]: form.is_valid()
Out[10]: True
In [11]: form.as_p()
Out[11]: u'<p><label for="id_test_field">Test field:</label> <input
id="id_test_field" type="text" name="test_field" maxlength="20"
/></p>'
In [12]: form.clean_data
Out[12]: {'test_field': u'DEFAULT'}
I will be glad for comments...
I would imagine poeple will want only one of these actions - pre-fill
an empty form (X)OR replace an empty value with the default
>
> > - specifying a custom BaseForm to inherit from? (someone could want to
> > have custom forms, that override as_p() for example) in
> > django.newforms.models
>
> This is an excellent idea. I've implemented it in [4220].
thanks
>
> > - allowing form_for_fields() to handle 2 fields of the same name (I
> > don't know how to do this one - you can make the name unique, but how
> > to maintain
>
> We could change the fields parameter to accept a list of (field_name,
> field_instance) tuples, perhaps?
>
> > - take validator_list into consideration when constructing a formfield
> > (this will probably require some nasty changes to be made to the
> > validation framework - either add a function - FormField mapping or
> > use FormFields in validator_list )
>
> I've been operating under the assumption that we would drop
> validator_list from models, in favor of a model field parameter such
> as "formfield", which would be a newforms.Field class object.
> Thoughts?
this is nice, can be a bit more typing though - but I have no other
(let alone better) idea... :-/
>
> > Please let me know if my attention is better spent someplace else
> > (perhaps rewriting the validators to Fields) - I have some free time
> > at the end of the year and would like to invest some of it into django
> > (and especially newforms, since we have a big project comming up and
> > we would love to use newforms from the neginning).
>
> Great! I'm excited that you can continue to help, as I have really
> appreciated your patches and contributions so far.
Glad to here this, have a look on ticket #3050 for more patches... :)
Feel free to take
> on any of the items mentioned in this e-mail, as long as we've all
> agreed on the right way to solve the problems. Rewriting the
> validators to Fields would be a much-welcomed contribution, too.
> Whatever you choose, let us know so that we don't duplicate work.
see new_fields.py for validators transformed into Fields. It is a
result of a few sed expressions (see gen_new_fields.sh ) and some
manual tweaks. I haven't tested it even for syntax errors, any help
would be welcome, especially tests and documentation (I suck at
these)...
I will continue working on those whenever I have some time (and mood ;) )
> Myself, I'm going to focus on newforms documentation, improving the
> form_for_model() unit tests and implementing formfield() for the
> remaining model Field classes.
looking forward to that
>
> Thanks again for your continued help on this -- we really appreciate it!
>
> --
> Adrian Holovaty
> holovaty.com | djangoproject.com
>
> >
>
--
Honza Král
E-Mail: [EMAIL PROTECTED]
ICQ#: 107471613
Phone: +420 606 678585
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---
field_default.patch
Description: Binary data
gen_new_fields.sh
Description: Bourne shell script
import urllib2
from django.conf import settings
from django.utils.translation import gettext, gettext_lazy, ngettext
from django.utils.functional import Promise, lazy
import re
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
alnum_re = re.compile(r'^\w+$')
alnumurl_re = re.compile(r'^[-\w/]+$')
ansi_date_re = re.compile('^%s$' % _datere)
ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
slug_re = re.compile(r'^[-\w]+$')
url_re = re.compile(r'^https?://\S+$')
lazy_inter = lazy(lambda a,b: str(a) % b, str)
class AlphaNumericField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not alnum_re.search(value):
raise ValidationError, gettext("This value must contain only letters, numbers and underscores.")
return value
class AlphaNumericURLField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not alnumurl_re.search(value):
raise ValidationError, gettext("This value must contain only letters, numbers, underscores, dashes or slashes.")
return value
class SlugField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not slug_re.search(value):
raise ValidationError, gettext("This value must contain only letters, numbers, underscores or hyphens.")
return value
class LowerCaseField(CharField):
def clean(self, value):
value = CharField.clean(value)
if value.lower() != value:
raise ValidationError, gettext("Uppercase letters are not allowed here.")
return value
class UpperCaseField(CharField):
def clean(self, value):
value = CharField.clean(value)
if value.upper() != value:
raise ValidationError, gettext("Lowercase letters are not allowed here.")
return value
class CommaSeparatedIntegerListField(CharField):
def clean(self, value):
value = CharField.clean(value)
new_value = []
for supposed_int in value.split(','):
try:
new_value.append( int(supposed_int) )
except ValueError:
raise ValidationError, gettext("Enter only digits separated by commas.")
return new_value
class CommaSeparatedEmailListField(CharField):
def clean(self, value):
"""
Checks that value is a string of e-mail addresses separated by commas.
Blank value values will not throw a validation error, and whitespace
is allowed around the commas.
"""
value = CharField.clean(value)
new_value = [ supposed_email.strip() for supposed_email in value.split(',') ]
for supposed_email in new_value
try:
isValidEmail(supposed_email, '')
except ValidationError:
raise ValidationError, gettext("Enter valid e-mail addresses separated by commas.")
return new_value
class ValidIPAddress4Field(CharField):
def clean(self, value):
value = CharField.clean(value)
if not ip4_re.search(value):
raise ValidationError, gettext("Please enter a valid IP address.")
return value
class NotEmptyField(CharField):
def clean(self, value):
value = CharField.clean(value)
value = value.strip()
if value == u'':
raise ValidationError, gettext("Empty values are not allowed here.")
return value
class OnlyDigitsField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not value.isdigit():
raise ValidationError, gettext("Non-numeric characters aren't allowed here.")
return value
class NotOnlyDigitsField(CharField):
def clean(self, value):
value = CharField.clean(value)
if value.isdigit():
raise ValidationError, gettext("This value can't be comprised solely of digits.")
return value
class IntegerField(CharField):
def clean(self, value):
value = CharField.clean(value)
# This differs from isOnlyDigits because this accepts the negative sign
if not integer_re.search(value):
raise ValidationError, gettext("Enter a whole number.")
return value
class OnlyLettersField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not value.isalpha():
raise ValidationError, gettext("Only alphabetical characters are allowed here.")
return value
class ValidEmailField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not email_re.search(value):
raise ValidationError, gettext('Enter a valid e-mail address.')
return value
class ValidURLField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not url_re.search(value):
raise ValidationError, gettext("A valid URL is required.")
return value
class ValidImageURLField(ValidURLField):
def clean(self, value):
value = ValidURLField.clean(value)
uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png'))
try:
uc(value, all_data)
except URLMimeTypeCheck.InvalidContentType:
raise ValidationError, gettext("The URL %s does not point to a valid image.") % value
return value
class ValidPhoneField(CharField):
def clean(self, value):
value = CharField.clean(value)
if not phone_re.search(value):
raise ValidationError, gettext('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % value
return value
class ValidQuicktimeVideoURLField(ValidURLField):
def clean(self, value):
"Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)"
value = ValidURLField.clean(value)
uc = URLMimeTypeCheck(('video/quicktime', 'video/mpeg',))
try:
uc(value, all_data)
except URLMimeTypeCheck.InvalidContentType:
raise ValidationError, gettext("The URL %s does not point to a valid QuickTime video.") % value
return value
class ValidHTMLField(CharField):
def clean(self, value):
import urllib, urllib2
value = CharField.clean(value)
try:
u = urllib2.urlopen('http://validator.w3.org/check', urllib.urlencode({'fragment': value, 'output': 'xml'}))
except:
# Validator or Internet connection is unavailable. Fail silently.
return
html_is_valid = (u.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid')
if html_is_valid:
return
from xml.dom.minidom import parseString
error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')]
raise ValidationError, gettext("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages)
return value
class WellFormedXmlField(CharField):
def clean(self, value):
from xml.dom.minidom import parseString
value = CharField.clean(value)
try:
parseString(value)
except Exception, e: # Naked except because we're not sure what will be thrown
raise ValidationError, gettext("Badly formed XML: %s") % str(e)
return value
class WellFmrmedXmlFragmentField(WellFormedXmlField):
def clean(self, value):
value = CharField.clean(value)
WellFormedXmlField.clean('<root>%s</root>' % value)
return value
class ExistingURLField(ValidURLField):
def clean(self, value):
value = ValidURLField.clean(value)
try:
headers = {
"Accept" : "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
"Accept-Language" : "en-us,en;q=0.5",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Connection" : "close",
"User-Agent": settings.URL_VALIDATOR_USER_AGENT
}
req = urllib2.Request(value,None, headers)
u = urllib2.urlopen(req)
except ValueError:
raise ValidationError, _("Invalid URL: %s") % value
except urllib2.HTTPError, e:
# 401s are valid; they just mean authorization is required.
# 301 and 302 are redirects; they just mean look somewhere else.
if str(e.code) not in ('401','301','302'):
raise ValidationError, _("The URL %s is a broken link.") % value
except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError, _("The URL %s is a broken link.") % value
return value
class ValidUSStateField(CharField):
def clean(self, value):
"Checks that the given string is a valid two-letter U.S. state abbreviation"
value = CharField.clean(value)
states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY']
if value.upper() not in states:
raise ValidationError, gettext("Enter a valid U.S. state abbreviation.")
return value
class NoProfanitiesField(CharField):
def clean(self, value):
"""
Checks that the given string has no profanities in it. This does a simple
check for whether each profanity exists within the string, so 'fuck' will
catch 'motherfucker' as well. Raises a ValidationError such as:
Watch your mouth! The words "f--k" and "s--t" are not allowed here.
"""
value = CharField.clean(value)
words_seen = [w for w in settings.PROFANITIES_LIST if w in value.lower()]
if words_seen:
from django.utils.text import get_text_list
plural = len(words_seen) > 1
raise ValidationError, ngettext("Watch your mouth! The word %s is not allowed here.",
"Watch your mouth! The words %s are not allowed here.", plural) % \
get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in words_seen], 'and')
return value
