I was merrily developing a web application using the Django development version. After some time had passed, I updated to version 1.2 alpha 1 SVN-12271. Now, I am getting form field default cleaning error messages like "Value u'A325' is not a valid choice." This is on a choice field with no possibility of an invalid choice. Also, I'm seeing "This field cannot be blank" when it can be blank, in fact. I don't think this is some kind of form field to model attribute indexing error. The application continues to work properly under Django 1.1.1. So, what major change has occurred in Django that would account for this? I've looked for backwards-incompatible changes in http://docs.djangoproject.com/en/dev/releases/1.2-alpha-1/ but don't really see anything.
Here are some big clues: 1) My field-by-field custom validation continues to work perfectly; only default validation is screwing up. 2) Only choice fields are affected, but some choice fields are not affected. 3) Of the affected choice fields, some are standard and some use the undocumented optgroup feature, so that doesn't seem to be a factor. Any ideas?
I really want to get back on the development version because I need the new object-level (row-level) permissions.
ADDED CODE
My pleasure, Zalew. This is my base model:
class BXEEP_L_Dataset(models.Model):
date_time = models.DateTimeField(editable=False, auto_now=True, auto_now_add=True,
help_text="Date and time created or last saved.")
unique_ID = models.CharField(max_length=20, blank=True, default="",
help_text="Unique identifier for problem")
project_name = models.CharField(max_length=55, blank=True, default="", help_text="Project name")
project_number = models.CharField(max_length=20, blank=True, default="", help_text="Project number")
description = models.CharField(max_length=55, blank=True, default="",
help_text="Problem description")
n_bolts = models.IntegerField(choices=BXEEP_BOLTS, blank=False, default=4,
help_text="4 or 8 bolts?")
stiffeners = models.BooleanField(blank=True, help_text="Stiffeners?")
cont_plates = models.BooleanField(blank=True, help_text="Continuity plates?")
partial_width = models.BooleanField(blank=True, help_text="Partial width plates?")
doubler_plate = models.BooleanField(blank=True, help_text="Doubler plate?")
column_top = models.BooleanField(blank=True, help_text="Top of column?")
shims = models.BooleanField(blank=True, help_text="Finger shims?")
flange_weld_type = models.CharField(max_length=11, choices=WELD_TYPE, blank=False, default="fillet",
help_text="Flange weld type")
flange_weld_size = models.IntegerField(blank=True, null=True, default=0, help_text="Flange weld size")
web_weld_type = models.CharField(max_length=11, choices=WELD_TYPE, blank=False, default="fillet")
web_weld_size = models.IntegerField(blank=True, null=True, default=0, help_text="Web weld size")
bolt_grade = models.CharField(max_length=8, choices=Bolt_grades, blank=False, default="A325",
help_text="Bolt grade")
db = models.FloatField(choices=Bolt_diameters, blank=False, default=0.750,
help_text="d<sub>b</sub>")
liw = models.BooleanField(blank=True, help_text="Load-indicating washers?")
end_pl_grade = models.CharField(max_length=8, choices=PL_grades_50, blank=False, default="A36",
help_text="End PL grade")
stiff_pl_grade = models.CharField(max_length=8, choices=PL_grades, blank=False, default="A36",
help_text="Stiffener PL grade")
cont_pl_grade = models.CharField(max_length=8, choices=PL_grades, blank=False, default="A36",
help_text="Continuity PL grade")
doubler_pl_grade = models.CharField(max_length=8, choices=PL_grades, blank=False, default="A36",
help_text="Doubler PL grade")
bm_profile = models.CharField(max_length=8, choices=W_profiles, help_text="Beam profile")
col_profile = models.CharField(max_length=8, choices=W_profiles, help_text="Column profile")
beam_grade = models.CharField(max_length=11, choices=W_grades, blank=False, default="A992",
help_text="Beam grade")
col_grade = models.CharField(max_length=11, choices=W_grades, blank=False, default="A992",
help_text="Column grade")
Muc = models.FloatField(help_text="M<sub>uc</sub>")
Vu = models.FloatField(help_text="V<sub>u</sub>")
Nu = models.FloatField(help_text="N<sub>u</sub>", blank=True, null=True, default=0.0)
Pcu = models.FloatField(help_text="P<sub>cu</sub>", default=0.0)
Vcu = models.FloatField(help_text="V<sub>cu</sub>", blank=True, null=True, default=0.0)
tp = models.FloatField(help_text="t<sub>p</sub>")
bp = models.FloatField(help_text="b<sub>p</sub>")
a = models.FloatField(help_text="a", default=0.0)
g = models.FloatField(help_text="g")
pfo = models.FloatField(help_text="p<sub>fo</sub>")
pfi = models.FloatField(help_text="p<sub>fi</sub>")
de = models.FloatField(help_text="d<sub>e</sub>")
pb = models.FloatField(blank=True, null=True, default=0.0, help_text="p<sub>b</sub>")
ts = models.FloatField(blank=True, null=True, default=0.0, help_text="t<sub>s</sub>")
tcp = models.FloatField(blank=True, null=True, default=0.0, help_text="t<sub>cp</sub>")
bcp = models.FloatField(blank=True, null=True, default=0.0, help_text="b<sub>cp</sub>")
td = models.FloatField(blank=True, null=True, default=0.0, help_text="t<sub>d</sub>")
hcol = models.FloatField(blank=True, null=True, default=0.0, help_text="h<sub>col</sub>")
tshim = models.FloatField(blank=True, null=True, default=0.0, help_text="t<sub>shim</sub>")
def __unicode__(self):
# return self.date_time
return u"%s" % (self.date_time)
The "not a valid choice" errors occurs on bolt_grade, even though it should be impossible to make an invalid selection. The "this field is required" errors occur on beam_profile, column_profile, even when a selection has been made, and on other fields (e.g. stiffener_grade, doubler_grade), even though they are not required. Here is the ModelForm:
class BXEEP_L_Form(ModelForm):
unique_ID = forms.CharField(max_length=20, required=False,
widget=forms.TextInput(attrs={"class": "short-char"}))
project_name = forms.CharField(max_length=55, required=False,
widget=forms.TextInput(attrs={"class": "long-char"}))
project_number = forms.CharField(max_length=20, required=False,
widget=forms.TextInput(attrs={"class": "short-char"}))
description = forms.CharField(max_length=55, required=False,
widget=forms.TextInput(attrs={"class": "long-char"}))
flange_weld_size = forms.IntegerField(min_value=2, required=False,
widget=forms.TextInput(attrs={"class": "short-int"}))
web_weld_size = forms.IntegerField(min_value=2, required=False,
widget=forms.TextInput(attrs={"class": "short-int"}))
stiff_pl_grade = forms.ChoiceField(choices=PL_grades, required=False)
cont_pl_grade = forms.ChoiceField(choices=PL_grades, required=False)
doubler_pl_grade = forms.ChoiceField(choices=PL_grades, required=False)
Muc = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
Vu = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
Nu = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}), required=False)
Pcu = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
Vcu = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}), required=False)
tp = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.125)
bp = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
a = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}), min_value=0.0)
g = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
pfo = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
pfi = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
de = forms.FloatField(widget=forms.TextInput(attrs={"class": "std-float"}))
pb = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}))
ts = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.125)
tcp = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.125)
bcp = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.125)
td = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.125)
hcol = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.0)
tshim = forms.FloatField(required=False, widget=forms.TextInput(attrs={"class": "std-float"}),
min_value=0.0625, max_value=0.250)
def clean(self):
...
<extensive custom validation omitted>
...
return cleaned_data
def __unicode__(self):
return self.unique_ID
class Meta:
model = BXEEP_L_Dataset
Finally, a snippet from the view:
if form.is_valid():
# Station K
# The form is saved into a new record only if it is valid.
new_dataset = form.save()
# Station L
# We need the new_dataset object so we can get the primary key from it, so we can't just say
# "form.save()."
dataset_id = new_dataset.pk
# Station M
# We reset the dataset_id from False to the new primary key.
#
# Now, with valid form data stored in the correct database record, the normalized version of
# the dataset, form.cleaned_data, may be processed, yielding preliminary analysis results
# in the form of unity checks (ratios) and status lines.
results = analyze_bxeep_l(form.cleaned_data)