Opened 16 years ago

Last modified 13 years ago

#7038 closed

FormWizard fails on forms with BooleanField when field is unselected — at Version 5

Reported by: anonymous Owned by: nobody
Component: contrib.formtools Version: dev
Severity: Keywords: FormWizard, BooleanField, hash failure
Cc: rajesh.dhawan@…, dev@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Ramiro Morales)

The form wizard fails to match its security hash when processing a form containing at least one BooleanField where the BooleanField's checkbox is unselected (e.g. False). This results in (on my machine) the form containing the BooleanField being redisplayed. If *all* the BooleanFields on a form are selected, it appears to work correctly.

I was able to workaround (not fix) by overriding the security_hash method as follows:

    def security_hash(self, request, form):

        for bf in form:
            if bf.field.__class__ != BooleanField:
                data = [(bf.name, bf.data or u'')] + [settings.SECRET_KEY]

        # Use HIGHEST_PROTOCOL because it's the most efficient. It requires
        # Python 2.3, but Django requires 2.3 anyway, so that's OK.
        pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
        return md5.new(pickled).hexdigest()

The problem appears (to my untrained eye) to be in the line assigning the value of data where bf.data = False and thus gets assigned .

I'm using SVN 7412.

Change History (6)

comment:1 by anonymous, 16 years ago

Component: Uncategorizeddjango.contrib.formtools

comment:2 by tbye@…, 16 years ago

When attempting to use the sample workaround above with rev. 7545 I hit an issue. Here's my updated sample to correct the problems I ran into.

def security_hash(self, request, form):
        for bf in form:
            if bf.field != BooleanField:
                 data = [(bf.name, bf.data or '')] + [settings.SECRET_KEY]

        # Use HIGHEST_PROTOCOL because it's the most efficient. It requires 
        # Python 2.3, but Django requires 2.3 anyway, so that's OK. 
        pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL) 
        return md5.new(pickled).hexdigest()

comment:3 by hanne.moa@…, 16 years ago

Keywords: hash failure added

I get this also... not an easy bug to detect when one has a wizard with many forms! maybe a better solution would be to explicitly set every unset BooleanField to False as soon as possible, that is: well before the hashing?

in reply to:  2 comment:4 by hanne.moa@…, 16 years ago

Replying to tbye@tbye.com:

When attempting to use the sample workaround above with rev. 7545 I hit an issue. Here's my updated sample to correct the problems I ran into.

def security_hash(self, request, form):

for bf in form:

if bf.field != BooleanField:

data = [(bf.name, bf.data or )] + [settings.SECRET_KEY]

This also means that only the last field per form, whatever that is, is hashed at all, as 'data' is replaced for almost every trip through the 'for'. Ergo, one might as well not have the hashing at all.

The real problem is that sql and web and boolean logic disagrees as to what a checkbox (CheckboxInput in django's case) is supposed to mean. Sql has three values for a bool: true, false, and unset. Web only has on/True and unset. Django has two types of boolean fields, using the same widget: BooleanField, which must be set and has two possible values: True and False, and NullboleanField, which is like sql in that it has three values: True, False and None (unset). The checkbox-widget however, obeys the web-rule of True vs. unset and ergo doesn't really fit with either of the fields =) See also #7051, #7190, #6937, #6914, #5957

comment:5 by Ramiro Morales, 16 years ago

Description: modified (diff)

by rishi, 16 years ago

django.contrib.formtools.7828.patch

Note: See TracTickets for help on using tickets.
Back to Top