Django错误:为关键字参数获取了多个值

时间:2009-12-21 18:35:20

标签: django django-forms

在使用构造函数overriden实例化Django表单时出现以下错误:

__init__() got multiple values for keyword argument 'collection_type'

__init__()函数(如下所示)与此类似,但# code替换为我的逻辑。请注意,我基本上重写了表单(这是一个ModelForm)构造函数。

def __init__(self, collection_type, user=None, parent=None, *args, **kwargs):
    # code
    super(self.__class__, self).__init__(*args, **kwargs)

创建错误的调用如下所示:

form = CreateCollectionForm(
    request.POST, 
    collection_type=collection_type, 
    parent=parent, 
    user=request.user
)

我看不出错误弹出的原因。

编辑:这是构造函数的完整代码

def __init__(self, collection_type, user=None, parent=None, *args, **kwargs):
    self.collection_type = collection_type
    if self.collection_type == 'library':
        self.user = user
    elif self.collection_type == 'bookshelf' or self.collection_type == 'series':
        self.parent = parent
    else:
        raise AssertionError, 'collection_type must be "library", "bookshelf" or "series"'
    super(self.__class__, self).__init__(*args, **kwargs)

编辑:Stacktrace

Environment:

Request Method: POST
Request URL: http://localhost:8000/forms/create_bookshelf/hello
Django Version: 1.1.1
Python Version: 2.6.1
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'libraries',
 'users',
 'books',
 'django.contrib.admin',
 'googlehooks',
 'registration']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware')


Traceback:
File "/Library/Python/2.6/site-packages/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.6/site-packages/django/contrib/auth/decorators.py" in __call__
  78.             return self.view_func(request, *args, **kwargs)
File "/Users/marcus/Sites/marcuswhybrow.net/autolib/libraries/forms.py" in     create_collection
  13.           form = CreateCollectionForm(request.POST,     collection_type=collection_type, user=request.user)

Exception Type: TypeError at /forms/create_bookshelf/hello
Exception Value: __init__() got multiple values for keyword argument 'collection_type'

3 个答案:

答案 0 :(得分:43)

您将collection_type参数作为关键字参数传递,因为您在调用表单构造函数时特别说collection_type=collection_type。所以Python将它包含在kwargs字典中 - 但是因为你还在该函数的定义中将它声明为位置参数,所以它会尝试将它传递两次,从而产生错误。

然而,你要做的事永远不会奏效。在 user=None, parent=None字典之前,你不能拥有*args ,因为那些已经是kwargs,并且args必须始终在kwargs之前。修复它的方法是删除collection_type,user和parent的显式定义,并从函数中的kwargs中提取它们:

def __init__(self, *args, **kwargs):
    collection_type = kwargs.pop('collection_type', None)
    user = kwargs.pop('user', None)
    parent = kwargs.pop('parent', None)

答案 1 :(得分:9)

这非常简单:你传递request.POST,然后才为collection_type设置参数。在什么request.POST将被放?没有地方。看这个:

In [8]: class A:
   ...:     def __init__(self, a, *args):
   ...:         print a, args
   ...:         
   ...:         

In [9]: A(None, a=None)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/gruszczy/Programy/logbuilder/<ipython console> in <module>()

TypeError: __init__() got multiple values for keyword argument 'a'

将request.POST移动到调用中的其他位置,但请记住,命名参数位于那些之后,而不是。

答案 2 :(得分:7)

Daniel Roseman的解决方案是更好地处理*args**kwargs的混合,但gruszczy的解释是正确的:

您已使用此签名定义CreateCollectionForm.__init__

def __init__(self, collection_type, user=None, parent=None, *args, **kwargs)

然后你就这样称呼它:

form = CreateCollectionForm(
    request.POST, 
    collection_type=collection_type, 
    parent=parent, 
    user=request.user
)
在通话期间隐式分配了

self。之后,Python只看到一个位置参数:request.POST,它被指定为collection_type,第一个参数。然后,处理关键字参数,当Python看到另一个关键字参数名称collection_type时,它必须抛出一个TypeError。

Daniel的解决方案是一个很好的解决方案,通过删除所有命名参数,可以更轻松地处理这样的事情,并将它们通过super()传递给更高级别的构造函数。或者,您需要将post字典作为__init__方法的第一个形式参数,并将其传递给超类。