1

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

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

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)

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

我已经尝试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是一个多态模型。我没有遇到任何麻烦。

4

2 回答 2

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将对话的自定义实现添加CSV 以进行表单呈现。

于 2013-11-13T08:01:51.390 回答
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()    

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

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

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

于 2013-11-14T03:29:54.440 回答