Flask-Classful

repository·main·Indexed 42 days ago

https://github.com/pallets-eco/flask-classful

An 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.

Tokens
7.5K
Snippets
28
Records
35
Agent score
54%

What's inside Flask-Classful

  1. What is Flask-Classful?

    main
    Flask-Classful is an extension for Flask that enables class-based views. It allows you to encapsulate specific context and behavior for routes and methods within a class structure. This provides a more powerful alternative to Flask's built-in MethodView and complements the use of Flask Blueprints.
  2. Create class-based views with FlaskView

    main

    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)
  3. Use special method names for RESTful routing

    main

    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.

    MethodRuleEndpointHTTP Method
    index/<class name>:indexGET
    get/<id><class name>:getGET
    post/<class name>:postPOST
    put/<id><class name>:putPUT
    patch/<id><class name>:patchPATCH
    delete/<id><class name>:deleteDELETE
  4. Use Python 3 type hints for automatic URL conversion

    main

    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)
  5. Use wrapper methods for fine-grained request processing

    main

    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.

    Available Wrapper Methods

    MethodScopeArguments
    before_request(self, name, *args, **kwargs)Runs before any view in the FlaskViewname (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 FlaskViewname (view name), response (must return a response)
    after_<view_method>(self, response)Runs after a specific view methodresponse (must return a response)

    Execution Order

    1. Any method registered with @app.before_request (Flask global)
    2. FlaskView.before_request
    3. FlaskView.before_<view_method>
    4. The actual view method
    5. FlaskView.after_<view_method>
    6. FlaskView.after_request
    7. Any method registered with @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"}
  6. Understand Flask-Classful routing: Prefixes and Bases

    main

    Flask-Classful constructs URLs using a combination of a route prefix and a route base:

    /{route_prefix}/{route_base}/

    • Route Prefix: An optional common base for a group of views (e.g., /api/). If not specified, no prefix is applied.
    • Route Base: The specific path for the view. This is either inferred from the 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.

  7. How Flask-Classful automatic routing works

    main

    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)
  8. Apply decorators to all methods in a FlaskView

    main

    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"
  9. Generate URLs for FlaskView using url_for

    main

    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 endpoint
    class 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")
  10. Handle multiple routes for a single method

    main

    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):
            ...
  11. Register custom base classes to avoid route collisions

    main

    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)
  12. Exclude methods from being registered as routes

    main

    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
            pass
    class SetupView(FlaskView):
        excluded_methods = ['setup']
    
        def setup(self):
            pass