Ошибка Django: получил несколько значений для аргумента ключевого слова
Я получаю следующую ошибку при создании формы 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 ответа
Вы передаете 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)
Это довольно просто: вы передаете request.POST и только после этого вы указываете аргумент для collection_type. На какой запрос.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 куда-нибудь еще в вызове, но помните, что именованные аргументы следуют за теми, которые не являются.
Решение Даниэля Роузмана состоит в том, чтобы обрабатывать смесь *args
а также **kwargs
лучше, но объяснение Грущчи является правильным:
Вы определили 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.
Решение Даниэля хорошее, удаляя все именованные параметры, гораздо проще обрабатывать подобные вещи и передавать их через super()
конструкторам более высокого уровня. Кроме того, вам нужно сделать словарь постов первым формальным параметром для вашего __init__
метод, и передать его до суперкласса.