Наследуют ли представления на основе класса django method_decorators?

Я использую представления на основе классов django. Предположим, что есть такой ListView:

@method_decorator(ensure_csrf_cookie, name='dispatch')
class SomeView(ListView):
    ...     

Если другое представление на основе классов наследует SomeView, наследует ли оно также и «ensure_csrf_cookie»? Или это должно быть определено для каждого подкласса явно?


person HsnVahedi    schedule 08.03.2019    source источник


Ответы (2)


Синтаксис @decorator — это просто синтаксический сахар, который преобразует это:

@decorator
class SomeClass(parent):
    pass

в это:

class SomeClass(parent):
    pass

SomeClass = decorator(SomeClass)

IOW, что бы ни делал decorator, делается после создания класса, поэтому, как правило, вы не можете рассчитывать на то, что он будет унаследован дочерними классами SomeClass - будет ли на самом деле унаследовано "то, что сделал декоратор" (или нет) действительно зависит как от того, «что сделал декоратор», так и от определения дочернего класса.

относительно вашего конкретного варианта использования: method_decorator используется для украшения данного метода вашего класса (метод dispatch в вашем примере). Если ваш дочерний класс не переопределяет этот метод, он будет найден в родительском классе. В этом случае вы действительно в конечном итоге будете использовать декорированный метод. Но если вы переопределите декорированный метод в своем подклассе, новый метод будет использоваться вместо родительского, поэтому он не будет автоматически декорирован, и вам придется снова применять декоратор.

FWIW, это довольно легко проверить самостоятельно:

>>> def decorator(func):
...     def wrapper(*args, **kw):
...         print("before %s(%s, %s)" % (func, args, kw)
... )
...         return func(*args, **kw)
...     return wrapper
... 
>>> from django.utils.decorators import method_decorator
>>> @method_decorator(decorator, name='foo')
... class Bar(object):
...     def foo(self):
...         print("%s.foo()"  % self)
... 
>>> b = Bar()
>>> b.foo()
before <function bound_func at 0x7fefab044050>((), {})
<Bar object at 0x7fefab09af10>.foo()
>>> class Quux(Bar): pass
... 
>>> q = Quux()
>>> q.foo()
before <function bound_func at 0x7fefab044050>((), {})
<Quux object at 0x7fefab041110>.foo()
>>> class Baaz(Bar):
...     def foo(self):
...         print("this is Baaz.foo")
... 
>>> bz = Baaz()
>>> bz.foo()
this is Baaz.foo
>>> 
person bruno desthuilliers    schedule 08.03.2019

Он должен быть явно определен для каждого подкласса. Поскольку method_decorator - это просто функция и выполняет некоторые вычисления (это зависит от того, как вы пишете декоратор), он вызовет ваш класс SomeView. Если вы наследуете SomeView, вам нужно явно использовать method_decorator для этого нового класса. Это может помочь.

person NVS    schedule 08.03.2019
comment
@HsnVahedi, увы, этот ответ неточен - он зависит от некоторых взаимодействий между тем, что делает декоратор, и тем, как вы определяете свой подкласс. - person bruno desthuilliers; 08.03.2019