正确覆盖ModelForm的表单字段,并保留模拟字段中的** kwargs

时间:2013-08-09 15:40:38

标签: django django-models django-forms

我的情况如下:

class MyModel(models.Model):
    field 1 = models.CharField(kwarg1 = value1, kwarg2 = value2, ...)

class MyCustomCharField(forms.CharField):
    def __init__(self, mandatarg1, ckwarg1 = cdefault1, ...):
       ...
    ...

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ['field1', ...]

    field1 = MyCustomCharField(mandatvalue1, ckwarg1 = cvalue1, ...)

问题是:在我的表单中,我放弃了kwarg1 = default1, kwarg2 = default2, ...,例如help_text="blablabla"max_length=255

有人想象一种保留这个默认参数的正确方法吗?


我试过了:

field1 = MyModel._meta.get_field('field1').formfield(form_class=MyCustomCharField, ckwarg1 = cvalue1)

它完美无缺,但是我无法传递mandatvalue1属性,所以我不能做我需要的事情!


field1 = MyCustomCharField(mandatvalue1, ckwarg1 = cvalue1, ..., **MyModel._meta.get_field('field1').__dict__)

但是在这里,我的词典中有太多的键,而Django崩溃了......


最后,我可以这样做:

field1 = MyCustomCharField(mandatvalue1, ckwarg1 = cvalue1, ..., help_text = MyModel._meta.get_field('field1').help_text, ...)

但我有很多值得像它一样复制,而且难以维护......有什么想法吗?我有点疯子,所以我真的很喜欢干净的方式(如果不是太多)

1 个答案:

答案 0 :(得分:0)

您可以使用**kwargs捕获并传递您未直接指定的所有关键字参数。 kwargs可以是任何东西,但惯例是使用该名称。它看起来如下:

def __init__(self, mandatarg1, ckwarg1=cdefault1, **kwargs)
    # do something
    super(MyCustomCharField, self).__init__(**kwargs)
    # do something else

由于双星号**,未明确定义的所有关键字参数都将打包在名为dict的{​​{1}}对象中。通过将kwargs传递给super的调用,在使用这些关键字参数调用super **kwargs函数之前,会再次解压缩这些值。

E.g。你可以拨打以下电话:

__init__

field1 = MyCustomCharField(mandatvalue1, max_length=255, ckwarg1 = cvalue1) 将如下所示:

kwargs

python将处理对super的调用,就像你调用了一样:

kwargs = {'max_length': 255}

对于具有单个星号的位置参数也可以这样做,惯例是使用super(MyCustomCharField, self).__init__(max_length=255) 执行此操作。 *args将是位置参数的元组,与参数传递的顺序一致。 args*args必须是函数定义中定义的最后一个参数。但是,您应该小心**kwargs:始终记住,在函数定义中,位置参数和关键字参数没有区别。因此,如果要扩展*args类,并且希望将字段作为位置参数传递,则必须将子类的MultiValueField方法中的每个参数视为位置参数。所以:

__init__

如果您只想指定关键字参数,或者如果要在超级位置参数之后指定位置参数,则执行此操作的常用方法是仅指定class MyCustomMultiValueField(forms.MultiValueField): def __init__(customarg1, customarg2=None, *args, **kwargs): # do something super(MyCustomMultiValueField, self).__init__(*args, **kwargs) # this won't work, as now customargs2 is (BooleanField(), DateField()), instead of fields MyCustomMultiValueField(1, (BooleanField(), DateField())) # you can still pass fields as a keyword argument MyCustomMultiValueField(1, fields=(BooleanField(), DateField())) *args作为参数:

**kwargs

一个常见的用例是当你想要指定额外的参数时,而其他一些代码依赖于基类的位置参数来创建你的子类。 Django模型和表单是您希望这样做以防止破坏代码的示例。

arguments in function definitions上的文档。