13 common decorators in Django

13 common decorators in Django

ยท

4 min read

Decorators in Django are a powerful tool that allows you to modify the behavior of a function or class.๐Ÿ’ช They are a form of metaprogramming, as they modify parts of the program at compile time. Here are some commonly used decorators:

  1. @login_required: This decorator is used to ensure that a view can only be accessed by logged-in users. If a user who is not logged in tries to access the view, they will be redirected to the login page.

     from django.contrib.auth.decorators import login_required
    
     @login_required
     def dashboard(request):
         # Only logged-in users can see their dashboard
         return render(request, 'dashboard.html')
    
  2. @permission_required('app.permission'): This decorator is used to ensure that a view can only be accessed by users with a certain permission. If a user without permission tries to access the view, a 403 Forbidden response is sent.

     from django.contrib.auth.decorators import permission_required
    
     @permission_required('drafts.can_edit')
     def vote(request, msg_id):
         # Only users with the 'can_edit' permission can access the drafts view
         return render(request, 'drafts.html', {'msg_id': msg_id})
    
  3. @csrf_exempt: This decorator marks a view as being exempt from CSRF protection. This should be used sparingly, and only when you're sure that your view doesn't need CSRF protection.

     from django.views.decorators.csrf import csrf_exempt
    
     @csrf_exempt
     def my_public_api_view(request):
         # This view is a public API and doesn't need CSRF protection
         return JsonResponse({'message': 'Hello, world!'})
    
  4. @require_POST: This decorator ensures that a view can only be accessed with a POST request. If a non-POST request is made to the view, a 405 Method Not Allowed response is sent.

     from django.views.decorators.http import require_POST
    
     @require_POST
     def vote(request, poll_id):
         # This view can only be accessed with a POST request
         return render(request, 'vote.html', {'poll_id': poll_id})
    
  5. @require_GET: This decorator ensures that a view can only be accessed with a GET request. If a non-GET request is made to the view, a 405 Method Not Allowed response is sent.

     from django.views.decorators.http import require_GET
    
     @require_GET
     def poll_results(request, poll_id):
         # This view can only be accessed with a GET request
         return render(request, 'results.html', {'poll_id': poll_id})
    
  6. @require_http_methods(["GET", "POST"]): This decorator ensures that a view can only be accessed with certain HTTP methods. If a request is made with a different method, a 405 Method Not Allowed response is sent.

     from django.views.decorators.http import require_http_methods
    
     @require_http_methods(["GET", "POST"])
     def vote(request, poll_id):
         # This view can only be accessed with a GET or POST request
         return render(request, 'vote.html', {'poll_id': poll_id})
    
  7. @cache_page(timeout): This decorator caches the result of a view for a certain amount of time. This can significantly improve performance for views that are expensive to compute.

     from django.views.decorators.cache import cache_page
    
     @cache_page(60 * 15)  # Cache for 15 minutes
     def poll_results(request, poll_id):
         # This view is expensive to compute, so we cache the results
         return render(request, 'results.html', {'poll_id': poll_id})
    
  8. @transaction.atomic: This decorator ensures that all database operations in the view are done in a single database transaction. This is useful for views that need to make multiple changes to the database and need to ensure that all changes are made successfully, or none at all.

     from django.db import transaction
    
     @transaction.atomic
     def vote(request, poll_id):
         # This view needs to make multiple changes to the database
         # We use @transaction.atomic to ensure that all changes are made successfully, or none at all
         return render(request, 'vote.html', {'poll_id': poll_id})
    
  9. @user_passes_test(test_func): This decorator checks whether a user passes a given test. If the user does not pass the test, they are redirected to the login page.

     from django.contrib.auth.decorators import user_passes_test
    
     def is_voter(user):
         return user.profile.is_voter
    
     @user_passes_test(is_voter)
     def vote(request, poll_id):
         # Only users who are voters can access the voting view
         return render(request, 'vote.html', {'poll_id': poll_id})
    
  10. @method_decorator(decorator_name): This decorator is used for class-based views. It applies a decorator to a method within a class-based view.

    from django.utils.decorators import method_decorator
    from django.views.decorators.http import require_POST
    from django.views import View
    
    class VoteView(View):
        @method_decorator(require_POST)
        def post(self, request, *args, **kwargs):
            # This view can only be accessed with a POST request
            return render(request, 'vote.html', {'poll_id': kwargs['poll_id']})
    
  11. @property: This decorator is used to define methods in classes that are intended to be accessed like attributes or properties, not as methods.

    class Circle:
        def __init__(self, radius):
            self._radius = radius
    
        @property
        def diameter(self):
            """Calculate diameter based on radius"""
            return self._radius * 2
    
    c = Circle(5)
    print(c.diameter)  # 10
    
  12. @staticmethod: This decorator is used inside a class to declare a method as a static method, which means it can be called on the class itself, rather than on instances of the class.

    class MathUtils:
        @staticmethod
        def add(a, b):
            return a + b
    
        @staticmethod
        def multiply(a, b):
            return a * b
    
    print(MathUtils.add(5, 3))  # 8
    print(MathUtils.multiply(5, 3))  # 15
    
  13. @classmethod: This decorator is used to declare a method as a class method, which means it can be called on the class itself, rather than on instances of the class. The first argument to a class method is always the class itself, commonly named cls.

    class Circle:
        def __init__(self, radius):
            self.radius = radius
    
        @classmethod
        def from_diameter(cls, diameter):
            return cls(diameter / 2)
    
    c = Circle.from_diameter(10)
    print(c.radius)  # 5.0
    

In the next article we're gonna get into some cool stuff with custom decorators. Stay tuned! ๐Ÿ˜Ž