Reputation: 7635
I use modelform_factory to generate modelforms with an extra form. For the forms with instances, the type field is disabled, for the extra form, the field is enabled.
On save() the forms does'nt validate because no data are in the POST for the disabled field. Even a custom clean method is not working (see this answer). I would like to skip the validation on the disabled fields or have a way to keep the instance data for this field.
models.py
class Attribute(models.Model):
shapefile = models.ForeignKey(Shapefile)
name = models.CharField(max_length=255)
type = models.IntegerField()
width = models.IntegerField()
precision = models.IntegerField()
def __unicode__(self):
return self.name
forms.py
FIELD_TYPE = [('', '--Choose a type--'),
(0, 'Integer'),
(1, 'Integer list'),
(2, 'Double Precision Float'),
(3, 'List of doubles'),
(4, 'String of ASCII chars'),
(5, 'Array of strings'),
(8, 'Raw Binary data'),
(9, 'Date'),
(10, 'Time'),
(11, 'Date and Time')]
class AttributeForm(ModelForm):
def __init__(self, *args, **kwargs):
super(AttributeForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['type'].widget.attrs['disabled'] = True
self.fields['width'].widget.attrs['readonly'] = True
self.fields['precision'].widget.attrs['readonly'] = True
type = forms.ChoiceField(choices=FIELD_TYPE)
class Meta:
model = Attribute
exclude = ['shapefile']
views.py
def editFields(request, shapefile_id):
layer_selected = Shapefile.objects.get(pk=shapefile_id)
attributes_selected= Attribute.objects.filter(shapefile__pk=shapefile_id)
attributesFormset = modelformset_factory(Attribute, form=AttributeForm, extra=1, can_delete=True)
if request.POST:
formset = attributesFormset(request.POST, queryset=attributes_selected)
formset.save()
else:
formset = attributesFormset(queryset=attributes_selected)
return render_to_response("ezmapping/editFields.html", {'shapefile': layer_selected, 'formset':formset}, context_instance=RequestContext(request))
Upvotes: 1
Views: 3302
Reputation: 37319
There are a number of approaches out there, but I think this one is fairly elegant (assuming it actually works; it looks right on first inspection but I haven't tested it).
https://stackoverflow.com/a/5994681/2337736
On your form, conditionally set the field as not required and then declare a custom clean method:
def __init__(self):
# as above, until here
self.fields['type'].widget.attrs['disabled'] = True
self.fields['type'].required = False
# then continue as above
def clean_type(self):
if self.instance and self.instance.pk:
return self.instance.type
else:
return self.cleaned_data['type']
Setting it as not required means that the field does not immediately short-circuit during validation of that field, and the custom clean method for the field returns the instance's unmodified value so that it is not overridden with None
when constructing the modified instance from the form. Custom clean methods are not called for required fields that are given empty values or no value at all.
Upvotes: 6