Django - 验证modelform_factory中的禁用字段

时间:2013-09-25 13:53:52

标签: django django-forms

我使用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))

1 个答案:

答案 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时不会覆盖它。从表单构造修改后的实例。对于给定空值或根本没有值的必填字段,不会调用自定义清理方法。