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
-~----------~----~----~----~------~----~------~--~---

Attachment: field_default.patch
Description: Binary data

Attachment: 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

Reply via email to