1

我使用 modelform_factory 生成带有额外表单的模型表单。对于带有实例的表单,类型字段被禁用,对于额外的表单,该字段被启用。

在 save() 上,表单不验证,因为禁用字段的 POST 中没有数据。即使是自定义清洁方法也不起作用(请参阅此答案)。我想跳过对禁用字段的验证,或者有办法保留该字段的实例数据。

模型.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

表格.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']

视图.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))
4

1 回答 1

5

有很多方法,但我认为这个相当优雅(假设它确实有效;第一次检查时它看起来正确,但我还没有测试过)。

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']

将其设置为不需要意味着该字段在验证该字段期间不会立即短路,并且该字段的自定义 clean 方法返回实例的未修改值,以便None在从表单构造修改的实例时不会覆盖它。对于被赋予空值或根本没有值的必填字段,不会调用自定义清理方法。

于 2013-09-25T17:04:12.413 回答