如何将模型默认值转换为Django Form,以便is_valid返回True

时间:2011-03-30 19:45:28

标签: django django-forms

我有一个Django modelForm,它排除了一些模型字段,因此当它在网页上使用时,这些字段是可用的。我想在API上使用相同的modelForm对象。

当我在网页上使用表单时,表单的呈现会考虑模型字段的默认值,表单将被呈现,并且提交的“最终”表单将包含这些值。同样地,我可以在创建过程中将初始dict传递给表单。

问题是,当您通过API公开modelForm时,没有默认值的初始呈现,导致它们显示在最终提交的表单中。这会导致is_valid返回false,因为表单“需要”通过表单的初始呈现填充其默认值的字段。

是否有一些设置可以让表单在验证时查看这些“默认”模型值,或者我是否只需编写验证代码来考虑它们?由于模型指定了默认值,因此看起来这应该可以正常工作,但事实并非如此。

除此之外,我如何找到字段来从中提取默认值作为我验证表单的点。到目前为止,我可以找到我编写的方法和方法,例如get_completion_format_display,但我没有看到模型类中字段的定义。

2 个答案:

答案 0 :(得分:2)

嗯,我已经想出了这个(有效),但我希望其他人有一个更优雅的解决方案。这正是我需要它做的,并且在通过Django进行调试时,我根本没有看到任何其他方法来执行此操作。实例参数在使用之前与初始数据合并,因此证明这是一种“修复”它的无效方法。

class MyForm(forms.ModelForm):
    """ Demonstrates using the default values from the data model so that form.is_valid() 
    will return True if the form has sufficient data (useful when using a form object with an api."""

    class Meta:
        model = MyModel
        exclude = ('status', 'uuid', 'submitted_on', 'completed_on', 
                   'last_attempt', 'failure_reason')

    def __init__(self, data=None, files=None, *args, **kwargs):
        """ Grab the default values from the model and add them to the form so it will validate """
        if data:
            for field in self.Meta.model._meta.fields:
                if (field.default != NOT_PROVIDED 
                    and field.name not in self.Meta.exclude 
                    and field.name not in data:
                    data[field.name] = field.default
        super(MyForm, self).__init__(data, files, *args, **kwargs)

答案 1 :(得分:0)

我有同样的问题,我决定在模型级解决它:

class DefaultingModelMetaClass(models.Model.__metaclass__):
    def __new__(cls, name, bases, attrs):
        obj = super(DefaultingModelMetaClass, cls).__new__(cls, name, bases, attrs)

        for f in obj._meta.fields:
            if not hasattr(f, 'orig_blank'):
                f.orig_blank = f.blank
            if f.has_default():
                # If a default value is provided we allow blank values for the field (not-required field)
                # We fill it with the default value when saved if it is still blank
                f.blank = True

        return obj

class DefaultingModel(models.Model):
    """
    Model class which makes fields not-required if they are providing a default value.
    Also fills in empty values for fields with default values on save.
    """

    __metaclass__ = DefaultingModelMetaClass

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        for f in self._meta.fields:
            if f.orig_blank:
                # We do not do anything with fields originally allowing blank values
                continue

            raw_value = getattr(self, f.attname)
            if f.has_default() and raw_value in validators.EMPTY_VALUES:
                setattr(self, f.attname, f.get_default())

        super(DefaultingModel, self).save(*args, **kwargs)