我使用modelform_factory来生成具有额外形式的模型。对于具有实例的表单,将禁用类型字段,对于额外的表单,将启用该字段。
在save()上,表单不会验证,因为禁用字段的POST中没有数据。即使是自定义清理方法也无效(see this answer)。我想跳过已禁用字段的验证,或者有办法保留此字段的实例数据。
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))
答案 0 :(得分:2)
有很多方法,但我认为这个方法相当优雅(假设它确实有效;它在第一次检查时看起来正确,但我没有测试过。)
https://stackoverflow.com/a/5994681/2337736
在表单上,有条件地将字段设置为不需要,然后声明自定义清理方法:
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']
将其设置为不需要意味着该字段在验证该字段期间不会立即短路,并且该字段的自定义清除方法返回实例的未修改值,以便在None
时不会覆盖它。从表单构造修改后的实例。对于给定空值或根本没有值的必填字段,不会调用自定义清理方法。