Skip to main content

Applying Decorators to Class Views

To apply middleware, authentication, or other wrappers to a class-based view in Flask, define the decorators class attribute on your View subclass. Applying decorators directly to the class using standard @decorator syntax will not affect the view function generated by as_view().

Applying Decorators to a View

When you call as_view(), Flask iterates through the decorators list and applies each one to the generated view function.

from flask import make_response
from flask.views import View

def add_x_parachute(f):
def new_function(*args, **kwargs):
resp = make_response(f(*args, **kwargs))
resp.headers["X-Parachute"] = "awesome"
return resp
return new_function

class Index(View):
# Decorators are applied to the view function returned by as_view()
decorators = [add_x_parachute]

def dispatch_request(self):
return "Awesome"

app.add_url_rule("/", view_func=Index.as_view("index"))

Understanding Decorator Order

The order of decorators in the decorators list is important. Flask applies them in the order they appear in the list. Because standard Python @decorator syntax is applied from bottom to top, the first decorator in the decorators list corresponds to the innermost (bottom) decorator.

def decorator_a(f): ...
def decorator_b(f): ...

class MyView(View):
# This is equivalent to:
# @decorator_b
# @decorator_a
# def view(...): ...
decorators = [decorator_a, decorator_b]

In this example, decorator_a wraps the original view logic first, and then decorator_b wraps the result of decorator_a.

Using Decorators with MethodView

The decorators attribute works identically in MethodView. This is useful for applying shared logic (like login requirements) across all HTTP methods defined in the class.

from flask.views import MethodView
from functools import wraps

def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# Implementation of login check
return f(*args, **kwargs)
return decorated_function

class UserAPI(MethodView):
decorators = [login_required]

def get(self, user_id):
return f"User {user_id}"

def post(self):
return "User created"

app.add_url_rule("/users/<int:user_id>", view_func=UserAPI.as_view("users"))

Important Considerations

Class Decoration vs. Attribute

Do not use @decorator syntax on the class itself if you want the decorator to wrap the request handling logic.

  • Incorrect: @auth_required class MyView(View): ... (This decorates the class object, not the view function).
  • Correct: class MyView(View): decorators = [auth_required] (This decorates the function used by the router).

State Safety and init_every_request

By default, View.init_every_request is True, meaning Flask creates a new instance of your class for every request. If you set init_every_request = False for performance, the same instance is shared across all requests.

If your decorators or dispatch_request method store data on self, this is only safe if init_every_request is True. If it is False, you must use flask.g to store request-global data to avoid leaking state between requests.

class SharedView(View):
init_every_request = False
decorators = [some_complex_decorator]

def dispatch_request(self):
# Use flask.g instead of self for request-specific data
return "Safe response"