使用模型清理功能以管理形式验证其他字段

时间:2013-11-05 17:26:46

标签: python django validation

我在我的模型中使用pickelField将csv数据序列化为数据库作为pandas数据帧。 Pickle字段不显示在管理表单上,因此我创建了一个额外的文本字段。

我正在关注向管理员表单添加自定义字段的this示例。

class ParameterDataTableAdminForm(forms.ModelForm):
    # create field to accept csv text
    data = forms.CharField(widget=forms.Textarea, required=True)

    class Meta:
        model = ParameterDataTable

    def __init__(self, *args, **kwargs):
        super(ParameterDataTableAdminForm, self).__init__(*args, **kwargs)
        # if instance exists this is an update
        if kwargs.has_key('instance'):
            instance = kwargs['instance']         
            # repr existing data
            csv_text = StringIO()
            instance.values.to_csv(csv_text,index=False)
            self.initial['data'] = csv_text.getvalue()

    def save(self, commit=True):
        model = super(ParameterDataTableAdminForm, self).save(commit=False)
        # convert the data to a pandas data frame
        model.values = pandas.read_csv(StringIO(self.cleaned_data['data']))

        # NEED TO VALIDATE MODEL.VALUES

        if commit:
            model.save()

        return model

class ParameterDataTableAdmin(admin.ModelAdmin):
    form = ParameterDataTableAdminForm

admin.site.register(ParameterDataTable, ParameterDataTableAdmin)

问题是在运行clean方法后,model.values被添加到模型中。我想使用模型清理方法来验证该字段。出于显而易见的原因,我试图避免在管理表单中验证模型字段。

我已经尝试在设置model.clean后立即显式运行model.values,但我得到一个异常而不是屏幕上的干净漂亮错误消息。

使用模型的clean方法验证字段value并将其与表单字段values相关联的最佳方法是什么?

编辑 - 我正在添加模型的相关部分

class ParameterDataTable(ParameterBase):
    values = PickledObjectField(null=False, blank=False, verbose_name=_("values"))

    def clean(self):
        super(ParameterDataTable, self).clean()
        if self.is_visible:
            raise ValidationError(_("Datatable cannot be visible"))

        if pd.isnull(self.values).any().any():
           raise ValidationError(_("Found missing values."))

我正在为我的模型使用PolymorphicModel。 ParameterBase是一个PolymorphicModel。我没有遇到任何麻烦。

2 个答案:

答案 0 :(得分:0)

不是在表单上创建其他字段,只需为values模型字段创建自定义表单字段,然后在此自定义字段中处理转换:

def validate_pandas_frame(value):
    if pd.isnull(value).any().any():
        raise ValidationError(_("Found missing values."))

class CSVTextarea(forms.Textarea):
    def render(self, name, value, attrs=None):
        csv_text = StringIO()
        output = value.to_csv(csv_text, index=False)
        return super(CSVTextarea, self).render(name, output, attrs)

class PickledCSVField(forms.Field):
    widget = CSVTextarea
    default_validators = [validate_pandas_frame]
    def to_python(self, value):
        return pandas.read_csv(StringIO(value))



class ParameterDataTableAdminForm(forms.ModelForm):
    # create field to accept csv text
    values = forms.PickledCSVField(required=True)

    class Meta:
        model = ParameterDataTable

    ...

修改:为表单呈现的对话添加了自定义forms.Textarea实施

答案 1 :(得分:0)

只是一个想法,但您可以在ModelForm的clean()方法中预先指定模型的值,而不是尝试在save()中执行此操作方法。

这样ValidationErrors应该整齐地传播到管理员。

class ParameterDataTableAdminForm(forms.ModelForm):
    # create field to accept csv text
    data = forms.CharField(widget=forms.Textarea, required=True)

    class Meta:
        model = ParameterDataTable

    def __init__(self, *args, **kwargs):
        super(ParameterDataTableAdminForm, self).__init__(*args, **kwargs)
        # if instance exists this is an update
        if kwargs.has_key('instance'):
            instance = kwargs['instance']         
            # repr existing data
            csv_text = StringIO()
            instance.values.to_csv(csv_text,index=False)
            self.initial['data'] = csv_text.getvalue()


    def clean(self):
        # clean to initially populate cleaned_data
        super(ParameterDataTableAdminForm, self).clean()  

        # parse cleaned_data and assign resulting pickled dataframe to values
        self.instance.values = pandas.read_csv(StringIO(self.cleaned_data['data']))            

        # run clean again, to catch values errors
        # or, even try, self.instance.clean()
        super(ParameterDataTableAdminForm, self).clean()    

这很难找到,但模型实例在ModelForm中的instance下可用。

  

绑定到模型对象的模型表单实例将包含一个实例   属性,使其方法可以访问该特定模型   实例

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method