What is Flask-Classful?
mainMethodView and complements the use of Flask Blueprints.repository·main·Indexed 42 days ago
https://github.com/pallets-eco/flask-classfulAn extension for Flask that provides class-based views, allowing developers to encapsulate route logic and behavior within classes. It offers a more powerful alternative to the standard MethodView and includes features like automatic routing, custom route prefixes, and RESTful method mapping. Version 0.17.0.dev.
MethodView and complements the use of Flask Blueprints.To define routes using Flask-Classful, create a subclass of flask_classful.FlaskView. You define your routes by implementing methods within this class. Once the class is defined, use the .register(app) method to attach the views to your Flask application instance.
from flask import Flask
from flask_classful import FlaskView
app = Flask(__name__)
class QuotesView(FlaskView):
def index(self):
return "All quotes"
def get(self, id):
return f"Quote {id}"
def random(self):
return "A random quote"
QuotesView.register(app)When using FlaskView, certain method names are automatically mapped to specific RESTful routes and HTTP methods. This allows you to define a standard API structure by simply naming your methods according to their purpose.
| Method | Rule | Endpoint | HTTP Method |
|---|---|---|---|
index | / | <class name>:index | GET |
get | /<id> | <class name>:get | GET |
post | / | <class name>:post | POST |
put | /<id> | <class name>:put | PUT |
patch | /<id> | <class name>:patch | PATCH |
delete | /<id> | <class name>:delete | DELETE |
In Python 3, you can use type hints on view function arguments to enable automatic type validation and conversion for URL variables. If a request provides a parameter that does not match the specified type, Flask-Classful will return a 404 HTTP status code instead of calling the view function.
By default, the following types are supported via the type_hints class attribute:
str -> 'string'int -> 'int'float -> 'float'UUID -> 'uuid'You can override the type_hints dictionary in your FlaskView subclass to map different types to specific Flask URL converters.
from flask_classful import FlaskView, route
from uuid import UUID
class TypingView(FlaskView):
def index(self):
return "Index"
@route('/<id>', methods=['POST'])
def post(self, id: str) -> str:
return "Post"
def int(self, arg: int):
return str(arg)
def uuid(self, arg: UUID):
return str(arg)Instead of using global @app.before_request decorators, FlaskView allows you to define specific wrapper methods within your class to handle logic for all views or specific view methods. This provides better granularity for tasks like tracking, authentication, or logging.
| Method | Scope | Arguments |
|---|---|---|
before_request(self, name, *args, **kwargs) | Runs before any view in the FlaskView | name (view name), *args, **kwargs |
before_<view_method>(self, *args, **kwargs) | Runs before a specific view method | *args, **kwargs |
after_request(self, name, response) | Runs after any view in the FlaskView | name (view name), response (must return a response) |
after_<view_method>(self, response) | Runs after a specific view method | response (must return a response) |
@app.before_request (Flask global)FlaskView.before_requestFlaskView.before_<view_method>FlaskView.after_<view_method>FlaskView.after_request@app.after_request (Flask global)from flask_classful import FlaskView
class WidgetsView(FlaskView):
# Runs before every method in this class
def before_request(self, name):
print(f"Starting {name}")
# Runs only before the 'get' method
def before_get(self):
print("Accessing a widget")
def get(self, id):
return {"id": id}
# Runs only after the 'post' method
def after_post(self, response):
print("Widget created")
return response
def post(self):
return {"status": "created"}Flask-Classful constructs URLs using a combination of a route prefix and a route base:
/{route_prefix}/{route_base}/
/api/). If not specified, no prefix is applied.FlaskView class name (minus the 'View' suffix) or explicitly set.Trailing Slashes: By default, Flask-Classful adds trailing slashes to routes without parameters. You can disable this by setting trailing_slash=False as a class attribute on your FlaskView or during registration.
Flask-Classful automatically generates routes for any method defined in a FlaskView class, provided the method name does not begin with an underscore (_).
For example, a method named index will create a route at the base path of the view, and a method named random will create a route at /random/ relative to the base path. This allows you to group related resource views into a single class without manually defining every route.
from flask import Flask
from flask_classful import FlaskView
app = Flask(__name__)
class QuotesView(FlaskView):
def index(self):
return "List of quotes"
def get(self, id):
return f"Quote {id}"
def random(self):
return "A random quote"
QuotesView.register(app)You can apply a decorator to every method within a FlaskView by defining a decorators attribute on the class. This is useful for applying authentication or logging to all endpoints in a view.
Example:
class WhataGreatView(FlaskView):
decorators = [login_required]
def this_is_secret(self):
return "Logged in"
def so_is_this(self):
return "Also logged in"To generate URLs for your FlaskView methods in templates or redirects, use Flask's url_for function with the format "<ClassName>:<method_name>".
If you have defined a custom endpoint using the @route decorator, use that custom endpoint name directly without the class prefix.
Example:
class DuckyView(FlaskView):
def index(self):
return "Duckies!"
def get(self, name):
return f"Duck {name}"
@route('/do_duck_stuff', endpoint='do_duck_stuff')
def post(self):
return "Um... Quack?"
# Usage:
url_for("DuckyView:index") # Returns URL for index
url_for("DuckyView:get", name="Howard") # Returns URL for get with param
url_for("do_duck_stuff") # Returns URL for custom endpointclass DuckyView(FlaskView):
def index(self):
return "Duckies!"
def get(self, name):
return "Duck %s" % name
@route('/do_duck_stuff', endpoint='do_duck_stuff')
def post(self):
return "Um... Quack?"
# Usage:
url_for("DuckyView:index")
url_for("DuckyView:get", name="Howard")
url_for("do_duck_stuff")If you apply multiple @route decorators to a single method, Flask-Classful prevents endpoint collisions by automatically appending an index to the endpoint name (e.g., QuotesView:show_quote_0, QuotesView:show_quote_1).
To avoid this automatic indexing and use a clean endpoint name, you must explicitly provide an endpoint argument in one of your @route decorators.
class QuotesView(FlaskView):
route_base = '/'
# Explicitly setting the endpoint avoids the automatic '_0' suffix
@route('/quote/<id>', endpoint='show_quote')
@route('/quote/show/<id>')
def show_quote(self, id):
...When subclassing FlaskView to create custom base classes, Flask-Classful's automatic method discovery might attempt to register your helper methods as routes.
While you can use excluded_methods to manually list methods to ignore, the recommended approach is to use the base_class keyword argument in the .register() method. By passing your intermediate base class to base_class, Flask-Classful will correctly identify and ignore all methods defined in that base class, registering only the unique methods in your actual view subclass.
class MyBaseView(FlaskView):
def foo(self):
return 'foo'
class MyChildView(MyBaseView):
def bar(self):
return 'bar'
# Passing base_class ensures 'foo' is not registered as a route
MyChildView.register(app, base_class=MyBaseView)By default, FlaskView ignores methods starting with an underscore (_). To exclude other specific methods that should not be exposed as API endpoints (e.g., internal setup or calculation methods), use the excluded_methods class attribute.
Example:
class SetupView(FlaskView):
excluded_methods = ['setup']
def setup(self):
# This method will NOT be registered as a route
passclass SetupView(FlaskView):
excluded_methods = ['setup']
def setup(self):
pass