0

我真的一直在拔头发来完成这件事。我的一个模型中有 2 个整数字段,如下所示:

#models.py

class TestModel(models.Model):
    """
    This is a test model.
    """

    max = models.IntegerField()
    min = models.IntegerField()

由于上述两个值是相互关联的,我希望它们使用自定义小部件。现在重点是,我希望这些字段使用单个自定义小部件(MultiWidget),但我也希望将值保存在数据库中的单独列中[不想解析内容,而且搜索功能将使用以上字段分开,所以只想单独存储它们]。

自定义小部件仅接受来自单个模型字段的值,因此我决定创建一个自定义表单字段以在上述模型的 ModelForm 中使用。

现在这就是我的表单的外观。

class MinMaxField(forms.MultiValueField):

    def __init__(self, *args, **kwargs):

        all_fields = ( 
            forms.CharField(),
            forms.CharField(),
            )   

        super(MinMaxField, self).__init__(all_fields, *args, **kwargs)

    def compress(self, values):
        if values:
            return '|'.join(values)
        return ''

class TestModelForm(forms.ModelForm):

    minmax = MinMaxField(widget=widgets.MinMaxWidget(),
             required=False)

    class Meta:
        model = models.TestModel
        fields = ('min', 'max', 'minmax')
        widgets = {
            'min' : forms.HiddenInput(),
            'max' : forms.HiddenInput(),
        }

    def full_clean(self, *args, **kwargs):
        if 'minmax_0' in self.data:
            newdata = self.data.copy()
            newdata['min'] = self.data['minmax_0']
            newdata['max'] = self.data['minmax_1']
            self.data = newdata
        super(TestModelForm, self).full_clean(*args, **kwargs)

上面的表单基本上隐藏了模型字段,只显示了minmax使用自定义小部件的字段,如下所示:

class MinMaxWidget(widgets.MultiWidget):

    def __init__(self, attrs=None):
        mwidgets = (widgets.Select(attrs=attrs, choices=MIN),
                   widgets.Select(attrs=attrs, choices=MAX))
        super(MinMaxWidget, self).__init__(mwidgets, attrs)

    def value_from_datadict(self, data, files, name):
        try:
            values = [widget.value_from_datadict(data, files, name + '_%s' % i)\ 
                      for i, widget in enumerate(self.widgets)]

            value = [int(values[0]), int(values[1])]
        except ValueError:
            raise ValueError('Value %s for %s did not validate. \
                              a list or a tuple expected' % (value, self.widget))
        return value

    def decompress(self, value):
        if value:
            if isinstance(value, list):
                return value
            return [value[0], value[1]]
        return [None, None]

    def format_output(self, rendered_widgets):
        rendered_widgets.insert(0, '<span class="multi_selects">')
        rendered_widgets.insert(-1, '<label id="min">Min</label>')
        rendered_widgets.append('<label id="max">Max</label></span>')
        return u''.join(rendered_widgets)

现在,一切正常,值分别保存到各自的字段中。但是当我试图用一个TestModel对象的实例编辑表单时,问题就出现了。在编辑的情况下,当呈现表单时,实际值存储在隐藏字段minmax输入字段中,而 minmax 字段没有值。[当然,因为它是一个表单域。]

我有什么选择

  1. 从和字段中预填充minmax表单字段的值。[注意:不使用 Javascript 或 jQuery]minmax

  2. 或者创建一个使用来自两个不同模型字段的值的 MultiWidget。

任何帮助,将不胜感激。谢谢。

4

1 回答 1

0

我目前遇到了类似的问题,并且有一种方法可以将小部件用于两个字段。我使用的是 1.4 版本,没有尝试过其他版本。

在你看来,你可能有这样的事情:

form = TestModelForm(instance=instance)

instance您要编辑的数据库中的对象在哪里。让我们看看 Django 在创建表单时在做什么

# django/forms/models.py

class BaseModelForm(BaseForm):
     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                  initial=None, error_class=ErrorList, label_suffix=':',
                  empty_permitted=False, instance=None):
          ...
          if instance is None:
              ...
          else:
              self.instance = instance
              object_data = model_to_dict(instance, opts.fields, opts.exclude)
          # if initial was provided, it should override the values from instance
          if initial is not None:
              object_data.update(initial)
          ...
          super(BaseModelForm, self).__init__(data, files, auto_id, prefix, 
                                              object_data, error_class, 
                                              label_suffix, empty_permitted)

然后,当呈现表单时,BoundField类使用它object_data为小部件分配初始值。

因此,您需要做的就是initial在表单构造函数中提供。

class TestModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        if 'instance' in kwargs:
            initial = dictionary with initial values
            initial.update(kwargs['initial'] or {})
        ...
        super(TestModelForm, self).__init__(initial=initial, *args, **kwargs)

还记得将您的字段添加到您的表单fields列表中。

这样您就没有两个未使用的隐藏小部件,无需使用 javascript 和 imo,代码更具解释性。

于 2013-07-23T15:47:52.597 回答