«Функции, помогающие динамически создавать декораторы для представлений».
из functools import partial , update_wrapper , wraps
class classonlymethod ( classmethod ):
def __get__ ( self , instance , cls = None ):
if instance is not None :
raise AttributeError ( «Этот метод доступен только для класса, а не для экземпляров.» )
return super () . __get__ ( экземпляр , cls )
def _update_method_wrapper ( _wrapper , decorator ):
метод bound_method _multi_decorate () недоступен в этой области. Чит-код,
# используя его в фиктивной функции.
@decorator
def dummy ( * args , ** kwargs ):
передать
update_wrapper ( _wrapper , dummy )
def _multi_decorate ( decorators , method ):
"" "
Украсить` method` одним или несколькими декораторами функций. `decorators` могут быть
одним или несколькими декораторами.
" ""
if hasattr ( decorators , '__iter__' ):
# Примените список / кортеж декораторов, если 'декораторы' один.
Функции
Decorator # применяются таким образом, что порядок вызова совпадает с порядком #, в котором они появляются в итеративном элементе.
декораторы = декораторы [:: - 1 ]
else :
декораторы = [ декораторы ]
def _wrapper ( self , * args , ** kwargs ):
# bound_method имеет сигнатуру, которую ожидает 'декоратор', т.е. нет
аргумента # 'self', но это закрытие над self, поэтому он может вызывать
# 'func'. Кроме того, оберните метод .__ get __ () в функцию, потому что новые
# атрибуты нельзя установить для связанных объектов метода, только для функций.
bound_method = partial ( method . __get__ ( self , type ( self )))
для dec в декораторах :
bound_method = dec ( bound_method )
return bound_method ( * аргументы , ** kwargs )
# Скопируйте любые атрибуты, которые декоратор добавляет к функции, которую он украшает.
для dec в декораторах :
_update_method_wrapper ( _wrapper , dec )
# Сохранить все существующие атрибуты 'метода', включая имя.
update_wrapper ( _wrapper , метод )
return _wrapper
[docs] def method_decorator ( decorator , name = '' ):
"" "
Преобразование декоратора функции в декоратор метода
" ""
# 'obj' может быть классом или функцией. Если 'obj' - это функция в момент
передачи # в _dec, в конечном итоге это будет метод класса,
# для которого он определен. Если «obj» - это класс, «имя» должно быть именем
# метода, который будет украшен.
def _dec ( obj ):
если не isinstance ( obj , type ):
декоратор , obj )
если нет ( name и hasattr ( obj , name )):
raise ValueError (
"Аргумент ключевого слова` name` должен быть именем метода "
" декорированного класса: % s . Вместо этого получено ' % s ' . " % ( obj , name )
)
method = getattr ( obj , name )
if not callable ( method ):
raise TypeError(
"Не может украсить ' % s ' , как это не вызываемым атрибут"
" % S ( % s )." % ( Имя , OBJ , метод )
)
_wrapper = _multi_decorate ( декоратор , метод )
SetAttr ( OBJ , имя , _wrapper )
return obj
# Не беспокойтесь о том, чтобы _dec выглядел как список / кортеж, потому что это
# бессмысленно.
если не hasattr ( decorator , '__iter__' ):
update_wrapper ( _dec , decorator )
# Измените имя, чтобы облегчить отладку.
obj = декоратор if hasattr ( декоратор , '__name__' ) else декоратор . __class__
_dec . __name__ = 'method_decorator ( % s )' % obj . __название__
return _dec
[docs] def decorator_from_middleware_with_args ( middleware_class ):
"" "
Как decorator_from_middleware, но возвращает функцию,
которая принимает аргументы для передачи в middleware_class.
Используйте как ::
cache_page = decorator_from_middleware_with_args (CacheMiddleware)
# ...
@cache_page (3600)
def my_view (request):
# ...
"" "
return make_middleware_decorator ( middleware_class )
[docs] def decorator_from_middleware ( middleware_class ):
"" "
Учитывая класс промежуточного программного обеспечения (не экземпляр), вернуть декоратор представления. Это
позволяет вам использовать функциональность промежуточного программного обеспечения для каждого представления. Промежуточное программное обеспечение
создается без переданных параметров.
" ""
return make_middleware_decorator ( middleware_class ) ()
def make_middleware_decorator ( middleware_class ):
def _make_decorator ( * m_args , ** m_kwargs ):
def _decorator ( view_func ):
middleware = middleware_class ( view_func , * m_args , ** m_kwargs )
@wraps ( view_func )
def _wrapped_view ( request , * args , ** kwargs ):
if hasattr ( middleware , 'process_request' ):
result = middleware . process_request ( запрос ),
если результат не равен None : вернуть результат, если hasattr ( middleware , 'process_view' ): result = middleware
. process_view ( request , view_func , args , kwargs ),
если результат не равен None : вернуть результат try : response = view_func ( request , * args , ** kwargs ), кроме Exception как e : if hasattr ( middleware , 'process_exception' ): result = промежуточное ПО .
process_exception ( request , e ),
если результат не равен None : вернуть результат поднять, если hasattr ( response , 'render' ) и callable ( response . render ): if hasattr ( middleware , 'process_template_response' ): response = middleware . process_template_response ( запрос , ответ )
# Отложить запуск process_response до тех пор, пока шаблон
# не будет отрисован:
if hasattr ( middleware , 'process_response' ):
def callback ( response ):
return middleware . process_response ( запрос , ответ )
ответ . add_post_render_callback ( обратный вызов )
else :
if hasattr ( middleware , 'process_response' ):
вернуть промежуточное ПО .process_response ( запрос , ответ )
return response
return _wrapped_view
return _decorator
return _make_decorator
[docs] def sync_and_async_middleware ( func ):
"" "
Отметить фабрику промежуточного программного обеспечения как возвращающую гибридное промежуточное программное обеспечение, поддерживающее оба
типа запросов.
" ""
func . sync_capable = Истинный
функ . async_capable = Истинное
возвращение функ
[docs] def sync_only_middleware ( func ):
"" "
Отметить фабрику промежуточного программного обеспечения как возвращающую промежуточное программное обеспечение синхронизации.
Это значение по умолчанию.
" ""
func . sync_capable = Истинный
функ . async_capable = Ложные
возвращение функ
[docs] def async_only_middleware ( func ):
"" "Отметить фабрику промежуточного программного обеспечения как возвращающую асинхронное промежуточное ПО." ""
func . sync_capable = Ложный
функ . async_capable = Истинное
возвращение функ