在课堂上添加**kwarg

pri*_*stc 3 python django

class StatusForm(ModelForm):

    bases = forms.ModelMultipleChoiceField(
            queryset=Base.objects.all(),  #this should get overwritten
            widget=forms.SelectMultiple,
        )

    class Meta:
        model = HiringStatus
        exclude = ('company', 'date')

    def __init__(self, *args, **kwargs):
        super(StatusForm, self).__init__(*args, **kwargs)
        if kwargs.has_key('bases_queryset'):
            self.fields['bases'].queryset = kwargs['bases_queryset']
Run Code Online (Sandbox Code Playgroud)

我想在这个表单中添加一个选项,允许我创建一个这样的表单:

form = StatusForm(bases_queryset=Base.objects.filter([...])
Run Code Online (Sandbox Code Playgroud)

但我不知何故需要在该类中"添加"该关键字参数,以便识别它.他们现在的方式,我只是得到这个错误:

__init__() got an unexpected keyword argument 'bases_queryset'

Kee*_*per 11

那是因为你正在将kwargs解包给超级构造函数.在调用super之前尝试将其放入:

if kwargs.has_key('bases_queryset'):
    bases_queryset = kwargs['bases_queryset']
    del kwargs['bases_queryset']
Run Code Online (Sandbox Code Playgroud)

但它不是一个理想的解决方案......

  • 更好的方法很简单:bases_queryset = kwargs.pop('bases_queryset',None)这将从字典中删除密钥并为其提供值(如果它存在),并且当密钥不存在时也初始化为None. (8认同)

Ale*_*lli 11

正如@Keeper所示,您不能将"new"关键字参数传递给超类.在你打电话给super之前,最好的办法是__init__:

bqs = kwargs.pop('bases_queryset', None)
Run Code Online (Sandbox Code Playgroud)

并且在那次__init__通话之后,检查if bqs is not None:而不是使用has_key(当然使用bqs而不是使用kwargs['bases_queryset']).

一种有趣的替代方法是进行"选择性调用"高阶函数.如果你同时拥有位置和命名参数(这对于元程序来说总是有点混乱;-),这有点乱,所以为了简化说明,假设你想要有选择地调用的函数只有"普通"命名参数(即没有**k其一).现在:

import inspect

def selective_call(func, **kwargs):
    names, _, _, _ = inspect.getargspec(func)
    usable_kwargs = dict((k,kwargs[k]) for k in names if k in kwargs)
    return func(**usable_kwargs)
Run Code Online (Sandbox Code Playgroud)

使用这种方法,在你的__init__,而不是__init__直接调用超级,你打电话 selective_call(super_init, **kwargs),让这个高阶函数做所需的"修剪".(当然,你需要使它梅西耶同时处理位置,并命名为ARGS,不错啊...... - - !)