Skip to main content

Overview

AbstractController is the base class for all controllers in Framefox. It provides essential methods for rendering templates, returning JSON responses, handling redirects, managing flash messages, and interacting with forms and authentication. All your controllers should extend this class to inherit these capabilities.

Usage

from framefox.core.controller.abstract_controller import AbstractController

class UserController(AbstractController):
    def index(self):
        users = self.get_users()
        return self.render('user/index.html', {'users': users})
    
    def create(self, request):
        user = User()
        form = self.create_form(UserForm, user)
        
        if form.is_valid():
            # Save user
            self.flash('success', 'User created successfully')
            return self.redirect(self.generate_url('user_list'))
        
        return self.render('user/create.html', {'form': form})

Constructor

__init__()

Initializes a new controller instance with dependency injection container and template renderer.
def __init__(self)
Note: Child controllers can override this method to inject their own dependencies. Example:
class CustomController(AbstractController):
    def __init__(self):
        super().__init__()
        self.my_service = self._container.get_by_name("MyService")

Methods

render()

Renders a template file with optional context data and returns an HTML response.
def render(self, template_path, context=None)
template_path
str
required
Path to the template file to render (relative to your templates directory)
context
dict
default:"None"
Dictionary of data to pass to the template for rendering
return
HTMLResponse
The rendered template as an HTML response
Example:
def show_profile(self, user_id: int):
    user = get_user_by_id(user_id)
    return self.render('profile/show.html', {
        'user': user,
        'last_login': user.last_login
    })

json()

Returns data as a JSON response with an optional HTTP status code.
def json(self, data: dict, status: int = 200)
data
dict
required
The dictionary data to serialize as JSON
status
int
default:"200"
HTTP status code for the response
return
JSONResponse
The data serialized as a JSON response
Example:
def api_get_users(self):
    users = User.query.all()
    return self.json({
        'users': [u.to_dict() for u in users],
        'count': len(users)
    })

def api_create_user(self, request):
    # Validation failed
    return self.json({
        'error': 'Invalid email address'
    }, status=400)

redirect()

Redirects the user to a specific URL with an optional HTTP status code.
def redirect(self, location: str, code: int = 302)
location
str
required
The URL to redirect to (can be absolute or relative)
code
int
default:"302"
HTTP status code for the redirect (302 = temporary, 301 = permanent)
return
RedirectResponse
A redirect response object
Example:
def delete_user(self, user_id: int):
    user = get_user_by_id(user_id)
    user.delete()
    
    self.flash('success', 'User deleted successfully')
    return self.redirect('/users')

def login(self, request):
    # After successful login, permanent redirect
    return self.redirect('/dashboard', code=301)

flash()

Adds a flash message to the session for displaying on the next request. Flash messages are typically used to show feedback after form submissions or actions.
def flash(self, category: str, message: str)
category
str
required
The category/type of the flash message (e.g., ‘success’, ‘error’, ‘warning’, ‘info’)
message
str
required
The message content to display to the user
return
None
This method does not return a value
Example:
def update_settings(self, request):
    settings = get_user_settings()
    settings.update(request.data)
    settings.save()
    
    self.flash('success', 'Settings updated successfully')
    return self.redirect('/settings')

def delete_account(self, user_id: int):
    try:
        user = get_user_by_id(user_id)
        user.delete()
        self.flash('success', 'Account deleted')
    except Exception as e:
        self.flash('error', f'Failed to delete account: {str(e)}')
    
    return self.redirect('/admin/users')

generate_url()

Generates a URL for a named route with optional parameters. This is useful for creating URLs dynamically without hardcoding paths.
def generate_url(self, route_name: str, **params)
route_name
str
required
The name of the route to generate a URL for
**params
kwargs
Additional parameters to include in the URL (e.g., path parameters, query strings)
return
str
The generated URL as a string
Example:
def show_user(self, user_id: int):
    user = get_user_by_id(user_id)
    edit_url = self.generate_url('user_edit', user_id=user_id)
    
    return self.render('user/show.html', {
        'user': user,
        'edit_url': edit_url
    })

def redirect_to_profile(self):
    user = self.get_user()
    profile_url = self.generate_url('user_profile', username=user.username)
    return self.redirect(profile_url)

create_form()

Creates a form instance from a form type class and binds it to an entity object. This is used for handling form creation, validation, and data binding.
def create_form(self, form_type_class, entity_instance)
form_type_class
Type
required
The form class to instantiate (should be a subclass of your form base class)
entity_instance
object
required
The entity object to bind to the form (e.g., a model instance)
return
Form
The created form instance bound to the entity
Example:
from src.form.user_form import UserForm
from src.entity.user import User

def edit_user(self, request, user_id: int):
    user = get_user_by_id(user_id)
    form = self.create_form(UserForm, user)
    
    if request.method == 'POST':
        form.bind(request.data)
        if form.is_valid():
            form.save()
            self.flash('success', 'User updated successfully')
            return self.redirect(self.generate_url('user_list'))
    
    return self.render('user/edit.html', {'form': form})

def create_user(self, request):
    user = User()  # Empty entity
    form = self.create_form(UserForm, user)
    
    if request.method == 'POST':
        form.bind(request.data)
        if form.is_valid():
            form.save()
            self.flash('success', 'User created successfully')
            return self.redirect(self.generate_url('user_list'))
    
    return self.render('user/create.html', {'form': form})

get_user()

Retrieves the currently authenticated user from the user provider.
def get_user(self, user_class=None)
user_class
Type
default:"None"
Optional specific user class to cast the result to
return
User | None
The current authenticated user instance, or None if not authenticated
Example:
def dashboard(self):
    user = self.get_user()
    if not user:
        return self.redirect('/login')
    
    return self.render('dashboard.html', {
        'user': user,
        'notifications': user.get_notifications()
    })

def profile(self):
    from src.entity.user import User
    user = self.get_user(User)
    
    return self.render('profile.html', {'user': user})

def api_current_user(self):
    user = self.get_user()
    if not user:
        return self.json({'error': 'Not authenticated'}, status=401)
    
    return self.json({
        'id': user.id,
        'username': user.username,
        'email': user.email
    })

Complete Example

Here’s a complete example showing multiple methods working together:
from framefox.core.controller.abstract_controller import AbstractController
from src.form.article_form import ArticleForm
from src.entity.article import Article

class ArticleController(AbstractController):
    def list(self):
        """Display list of all articles"""
        articles = Article.query.all()
        return self.render('article/list.html', {
            'articles': articles
        })
    
    def show(self, article_id: int):
        """Display a single article"""
        article = Article.query.get(article_id)
        if not article:
            self.flash('error', 'Article not found')
            return self.redirect(self.generate_url('article_list'))
        
        return self.render('article/show.html', {
            'article': article
        })
    
    def create(self, request):
        """Create a new article"""
        user = self.get_user()
        if not user:
            return self.redirect('/login')
        
        article = Article()
        article.author = user
        form = self.create_form(ArticleForm, article)
        
        if request.method == 'POST':
            form.bind(request.data)
            if form.is_valid():
                form.save()
                self.flash('success', 'Article created successfully')
                return self.redirect(
                    self.generate_url('article_show', article_id=article.id)
                )
        
        return self.render('article/create.html', {'form': form})
    
    def api_list(self):
        """API endpoint returning articles as JSON"""
        articles = Article.query.all()
        return self.json({
            'articles': [a.to_dict() for a in articles],
            'count': len(articles)
        })

See Also

  • ControllerResolver - Learn how controllers are discovered and resolved
  • Routing Guide - Learn how to define routes that map to controller methods
  • Forms - Learn more about form handling in Framefox

Build docs developers (and LLMs) love