Django — передача значения атрибута в as_view в TemplateView

#python #django #django-templates

#python #django #django-шаблоны

Вопрос:

Это мой взгляд (упрощенный):

 class MyView(TemplateView):
    def __init__(self):
        self.foo = 'bar'
        super(MyView, self).__init__()
  

Это в urls.py:

 url(
    r'^/foo/$',
    MyView.as_view(foo='baz'), name='my_view'
)
  

Когда я запускаю это, я получаю следующую ошибку:

 TypeError: MyView() received an invalid keyword 'foo'. as_view only accepts arguments that are already attributes of the class.
  

Почему?Я думал, что это сработает. :/

По крайней мере, согласно этому сообщению: http://reinout.vanrees.org/weblog/2011/08/24/class-based-views-walkthrough.html#class-view

Если я правильно понял это, это должно было установить атрибут foo на 'baz' переданное значение as_view . Без каких-либо атрибутов as_view значение должно быть 'bar' , как определено в __init__ .

Ответ №1:

Вы явно устанавливаете значение для экземпляра класса в __init__() . Однако сам класс по-прежнему не имеет атрибута foo , поскольку он не знает о динамических атрибутах в экземплярах: hasattr(MyView, 'foo') всегда возвращает False .

Это будет работать так, как вы ожидали, что ваш код будет работать:

 class MyView(TemplateView):
    foo = 'bar'

url(
    r'^/foo/$',
    MyView.as_view(foo='baz'), name='my_view'
)
  

Комментарии:

1. Изменит ли это это значение только для этого экземпляра представления или для самого класса? Что произойдет, если у меня есть другая привязка URL без параметра в urls.py и это называется в честь этого вопроса из вопроса? Будет ли значение внутри 'bar' или 'baz' ?

2. @morgoth84 MyView Класс будет создан с использованием аргументов ключевого слова, переданных as_view методу. Это не изменит ни одного атрибута в самом классе. Если другая привязка url не передает другое значение для foo , значение для MyView экземпляра будет по умолчанию 'bar' .

3. @morgoth84 Еще одна вещь, вы можете переопределить __init__ View подклассы, но вам нужно захватить все аргументы ключевого слова ( __init__(self, **kwargs) ) и передать их вызову super , иначе вы сломаете материал.

Ответ №2:

Исходный код View класса Django имеет это, хотя:

 if not hasattr(cls, key):
    raise TypeError
  

Таким образом, недостаточно создать attr для экземпляра в __init__ … он должен существовать в самом классе:

 class MyView(TemplateView):
    foo = 'bar'
  

Комментарии:

1. Реализация __init__ on в Django по умолчанию View будет обрабатывать все аргументы ключевого слова и устанавливать их в экземпляре. Ваша реализация __init__ фактически нарушит работу, если вы попытаетесь передать другой аргумент ключевого слова.