Skip to content

Latest commit

 

History

History
106 lines (88 loc) · 3.2 KB

File metadata and controls

106 lines (88 loc) · 3.2 KB

Examples

Wrapping a simple logic

A decorator can be used to wrap a simple piece of logic to the decorated function.

It does so by creating a new function, injecting the logic, and calling the original function to retrieve the result.

  • Example 1

    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):
                if request.method not in request_method_list:
                    logger.warning(
                        'Method Not Allowed (%s): %s', request.method, request.path,
                        extra={'status_code': 405, 'request': request}
                    )
                    return HttpResponseNotAllowed(request_method_list)
                return func(request, *args, **kwargs)
            return inner
        return decorator
    
    require_GET = require_http_methods(["GET"])
    require_GET.__doc__ = "Decorator to require that a view only accepts the GET method."
    
    require_POST = require_http_methods(["POST"])
    require_POST.__doc__ = "Decorator to require that a view only accepts the POST method."
    from django.views.decorators.http import require_GET, require_POST
    from django.contrib.auth.decorators import login_required
    from django.contrib.admin.views.decorators import staff_member_required
    from django.shortcuts import redirect, render
    from django.core.urlresolvers import reverse
    
    @require_GET
    def index(request):
        return HttpResponse("Hello, world!")
    
    @require_GET
    @login_required
    def dashboard(request):
        return render(request, 'dashboard.html')
    
    @require_POST
    @staff_member_required
    def add(request):
        # ...
        return redirect(reverse('dashboard'))

    For readability, it is often a good practice that this kind of decorator does not change the signature (i.e. parameters and return type) of the decorated function. In the example above each function is a Django view, and after being decorated they are still Django views.

  • Example 2

    (Script available)

    import time
    import functools
    
    def timed(func):
        @functools.wraps(func)
        def __new_func(*args, **kwargs):
            start = time.time()
            try:
                return func(*args, **kwargs)
            finally:
                end = time.time()
                print("{} took {} seconds".format(func.__name__, end - start))
    
        return __new_func
    
    @timed
    def f(x):
        for i in range(10 ** x):
            pass
    
    if __name__ == '__main__':
        f(5)
        f(6)
        f(7)
        f(8)

Prev / Up / Next