Подтвердить что ты не робот

Ошибка 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
)

Я не вижу причин, по которым появляется ошибка.

EDIT: Вот полный код конструктора

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)

EDIT: 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'
4b9b3361

Ответ 1

Вы передаете аргумент collection_type в качестве аргумента ключевого слова, потому что вы конкретно говорите collection_type=collection_type в своем вызове конструктору формы. Таким образом, Python включает его в словарь kwargs, но поскольку вы также объявили его как позиционный аргумент в определении этой функции, он пытается передать его дважды, следовательно, ошибку.

Однако то, что вы пытаетесь сделать, никогда не будет работать. У вас не может быть user=None, parent=None перед словарем *args, так как они уже являются kwargs, и args всегда должны появляться перед kwargs. Способ исправления заключается в том, чтобы удалить явное определение collection_type, пользователя и родителя и извлечь их из kwargs внутри функции:

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

Ответ 2

Это довольно просто: вы передаете 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 где-нибудь еще в вызове, но помните, что именованные аргументы приходят после тех, которые не являются.

Ответ 3

Решение Даниэля Роземана должно обрабатывать смесь *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.

Решение Daniel является хорошим, удалив все именованные параметры, гораздо проще обрабатывать такие вещи и передавать их через super() в конструкторы более высокого уровня. В качестве альтернативы вам нужно сделать первый словарь в качестве первого формального параметра для вашего метода __init__ и передать его в суперкласс.