2009-12-05 8 views
5
share引数が True(ミドルウェアで処理されている)の場合、ビューを実行したくないときに、このデコレータを使用しています。

デコレータへの引数の追加

class no_share(object): 
    def __init__(self, view): 
     self.view = view 

    def __call__(self, request, *args, **kwargs): 
     """Don't let them in if it's shared""" 

     if kwargs.get('shared', True): 
      from django.http import Http404 
      raise Http404('not availiable for sharing') 

     return self.view(request, *args, **kwargs) 

現在、次のように動作しています:

@no_share 
def prefs(request, [...]) 
@no_share('prefs') 
def prefs(request, [...]) 
@no_share('prefs') 
def prefs(request, [...]) 
しかし、私はこのように動作するように、少し機能を拡張したいと思います:

@no_share('prefs') 
def prefs(request, [...]) 

私の質問は、追加の引数を受け入れるようにこのデコレータクラスを変更する方法は?

答えて

7

私は、thisのBruce Eckelの記事を参考にしてください。

UPD: 記事によると、あなたのコードは次のようになります。必要に応じて

class no_share(object): 
    def __init__(self, arg1): 
     self.arg1 = arg1 

    def __call__(self, f): 
     """Don't let them in if it's shared""" 

     # Do something with the argument passed to the decorator. 
     print 'Decorator arguments:', self.arg1 

     def wrapped_f(request, *args, **kwargs): 
      if kwargs.get('shared', True): 
       from django.http import Http404 
       raise Http404('not availiable for sharing') 
      f(request, *args, **kwargs)    
     return wrapped_f 

が使用されるように:

@no_share('prefs') 
def prefs(request, [...]) 
1
class no_share(object): 
    def __init__(self, foo, view): 
     self.foo = foo 
     self.view = view 
+0

、私はすでにことを試してみましたが、私はそれが動作しませんでしたので、Djangoは違ったか何かうまくいくと思います。私はinitに 'print 'blah" 'を入れようとしましたが、devサーバを起動したときに私が得たのはたくさんの' blah's 'でした。それ以降はそれ以上のものはありません... – priestc

+1

これは、__init__は一度しか呼び出されませんが、これで飾る各ビュー関数の定義には一度しか呼ばれません。 __call__は、サーバーが要求に応答するためにビュー関数を実行するたびに呼び出されます。 この回答は正しい方向です。あなたのケースに特有のより完全な答えを私の答えに見てください。 – taleinat

0

あなたが間違ってどこかにこれを取得しているようですので、ここでは、あなたが間違っていることを見るのに役立つより完全な例があります。これをドロップインとして使用すると効果的です。

class no_share(object): 
    def __init__(self, view, attr_name): 
     self.view = view 
     self.attr_name = attr_name 

    def __call__(self, request, *args, **kwargs): 
     """Don't let them in if it's shared""" 

     if kwargs.get(self.attr_name, True): 
      from django.http import Http404 
      raise Http404('not availiable for sharing') 

     return self.view(request, *args, **kwargs) 
4

Li0liQが言及したブルース・Eckel氏articleはこれを考え出すのに役立つはずです。引数のあるデコレータとアウトのないデコレータは、動作が多少異なります。大きな違いは、引数を渡すと、__call__メソッドが__init__で一度呼び出され、装飾された関数が呼び出されるたびに呼び出される関数を返すことになっていることです。引数がないときは、装飾された関数が呼び出されるたびに__call__メソッドが呼び出されます。

これはどういう意味ですか? @no_arg_decoratorに対して__init__と__call__が呼び出される方法は、@decorator('with','args')に対して呼び出される方法とは異なります。

あなたのためにこのトリックを行うデコレータは2つあります。 @no_share_on(...)デコレータは、常にカッコで使用している限り使用できます。

def sharing_check(view, attr_name, request, *args, **kwargs): 
    if kwargs.get(attr_name, True): 
     from django.http import Http404 
     raise Http404('not availiable for sharing') 

    return view(request, *args, **kwargs) 

class no_share(object): 
    """A decorator w/o arguments. Usage: 
    @no_share 
    def f(request): 
     ... 
    """ 
    def __init__(self, view): 
     self.view = view 

    def __call__(self, request, *args, **kwargs): 
     return sharing_check(self.view, 'sharing', request, *args, **kwargs) 

class no_share_on(object): 
    """A decorator w/ arguments. Usage: 
    @no_share_on('something') 
    def f(request): 
     ... 
    --OR-- 
    @no_share_on() 
    def g(request): 
     ... 
    """ 
    def __init__(self, attr_name='sharing'): 
     self.attr_name = attr_name 

    def __call__(self, view): 
     def wrapper_f(request, *args, **kwargs): 
      return sharing_check(view, self.attr_name, request, *args, **kwargs) 
1

閉鎖がここで機能すると思われます。

def no_share(attr): 
    def _no_share(decorated): 
     def func(self, request, *args, **kwargs): 
      """Don't let them in if it's shared""" 

      if kwargs.get(attr, True): 
       from django.http import Http404 
       raise Http404('not availiable for sharing') 

      return decorated(request, *args, **kwargs) 
     return func 
    return _no_share 
0

利益のために、私はこれは少し遅れイア知っている..しかし、私は、任意のは、(それが質問を頼まれた時に存在していなかったせいか)物事のこの方法については言及して見ませんでしたが、完成度 Django自身がそのようなことをどのように実装したかを見ておくと便利です。見て:私が言及している必要があります

django.views.decorators.http.require_http_methods https://github.com/django/django/blob/master/django/views/decorators/http.py

from functools import wraps 
from django.utils.decorators import decorator_from_middleware, available_attrs 

def require_http_methods(request_method_list): 
    """ 
    Decorator to make a view only accept particular request methods. Usage:: 

    @require_http_methods(["GET", "POST"]) 
    def my_view(request): 
    # I can assume now that only GET or POST requests make it this far 
    # ... 

    Note that request methods should be in uppercase. 
    """ 
    def decorator(func): 
     @wraps(func, assigned=available_attrs(func)) 
     def inner(request, *args, **kwargs): 
      # .. do stuff here 

      return func(request, *args, **kwargs) 
     return inner 
    return decorator 
関連する問題