check if form has changed

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# $Id: form_changed.py 602 2008-02-29 15:02:58Z tguettler $
# $HeadURL: svn+ssh://svnserver/svn/modwork/trunk/utils/form_changed.py $

# Python
import logging
import itertools

# Django
from django import newforms as forms
from django.db import models

def form_changed(form):
    debug=False
    assert form.is_valid()

    def diff_value(value, initial, name):    
        # If this is an instance of a model, then compare with the primary key
        cls=getattr(value, "__class__")
        if issubclass(cls, models.Model):
            if debug:
                logging.info(u"form_changed using primary key as value: %s %s %s" % (
                        form, name, value))
                
            value=getattr(value, value._meta.pk.name)

        if (not value) and (not initial) and (value==False or value!=0):
            # None and empty string are equal
            if debug:
                logging.info(u"form_changed no diff: (None) %r %s %s %s" % (
                    form, name, value, initial))
            return False
        if value and not initial:
            if debug:
                logging.info(u"form_changed diff: value + not %r %s %r %s %r" % (
                    form, name, value, type(value),
                    initial))
            return True
        if unicode(value)!=unicode(initial):
            if debug:
                logging.info(u"form_changed diff: %r %s %s %s %s" % (form, name, value, type(value),
                                                                        initial))
            return True
        if debug:
            logging.info(u"form_changed no diff: %r %s %s %s" % (form, name, value, initial))
        return False

    for name, field in form.fields.items():
        initial = form.initial.get(name, field.initial)
        if callable(initial):
            initial = initial()
        if initial is None:
            if isinstance(field, forms.ChoiceField) and not isinstance(field, forms.MultipleChoiceField):
                if field.choices:
                    initial=None
                    # field.choices can be QuerySetIterator
                    # get first entry without getting whole Query.
                    for initial_tuple in field.choices:
                        initial=initial_tuple[0]
                        break

        value=form.cleaned_data.get(name)
        if isinstance(value, (list, tuple)):
            if initial==None:
                if not value:
                    if debug:
                        logging.info(u"form_changed no diff: %r %s %s %s" % (form, name, value, initial))
                    continue
                if debug:
                    logging.info(u"form_changed diff: %r %s %s %s" % (form, name, value, initial))
                return True
                
            assert isinstance(initial, (list, tuple)), 'initial ist not a list: %s %s value=%s' % (
                field, initial, value)
            if len(initial)!=len(value):
                if debug:
                    logging.info(u"form_changed diff length of lists different: %r %s %s %s" % (
                        form, name, value, initial))
                return True
            for value_item, initial_item in itertools.izip(value, initial):
                if diff_value(value_item, initial_item, name):
                    return True
        else:        
            if diff_value(value, initial, name):
                return True
    return False

Comments

guettli (on September 17, 2008):

At least since django 1.0 forms have method has_changed() and an attribute "changed_data". I (the author of this snippet) will use has_changed() instead of this snippet in new code.

#

(Forgotten your password?)

You may use Markdown syntax here, but raw HTML will be removed.