Base Views¶
The BaseView class provides a foundation for creating class-based views in Wiverno. It automatically dispatches requests to methods based on HTTP method.
Module: wiverno.views.base_views¶
Overview¶
Class-based views are an alternative to function-based views. They allow you to organize view logic in classes with methods for different HTTP methods:
- GET -
get(request) - POST -
post(request) - PUT -
put(request) - DELETE -
delete(request) - PATCH -
patch(request) - Other HTTP methods -
connect(request),head(request),options(request),trace(request)
Basic Usage¶
from wiverno.main import Wiverno
from wiverno.views.base_views import BaseView
from wiverno.core.requests import Request
class ItemsView(BaseView):
def get(self, request: Request) -> tuple[str, str]:
return "200 OK", "List of items"
def post(self, request: Request) -> tuple[str, str]:
return "201 CREATED", "Item created"
app = Wiverno()
app.route("/items")(ItemsView())
Class Definition¶
BaseView¶
Base class for class-based views.
from wiverno.views.base_views import BaseView
class MyView(BaseView):
"""Define methods for each HTTP method you want to handle."""
def get(self, request):
return "200 OK", "GET response"
def post(self, request):
return "201 CREATED", "POST response"
Methods¶
HTTP Method Handlers¶
Define methods named after HTTP methods (lowercase) to handle requests:
get(request) -> tuple[str, str]¶
Handle GET requests.
post(request) -> tuple[str, str]¶
Handle POST requests.
class UserListView(BaseView):
def post(self, request):
# request.data contains POST body
name = request.data.get('name')
return "201 CREATED", f"User {name} created"
put(request) -> tuple[str, str]¶
Handle PUT requests (full resource replacement).
class UserDetailView(BaseView):
def put(self, request):
# request.data contains new resource data
return "200 OK", "User updated"
patch(request) -> tuple[str, str]¶
Handle PATCH requests (partial resource update).
class UserDetailView(BaseView):
def patch(self, request):
# request.data contains partial update
return "200 OK", "User partially updated"
delete(request) -> tuple[str, str]¶
Handle DELETE requests.
connect(request), head(request), options(request), trace(request)¶
Handle other HTTP methods.
class ResourceView(BaseView):
def head(self, request):
return "200 OK", ""
def options(self, request):
return "200 OK", "GET,POST,PUT,DELETE"
__call__(request) -> tuple[str, str]¶
The magic method that makes the view callable. Automatically dispatches to the appropriate HTTP method handler.
Parameters:
request(Request): The incoming request object
Returns: tuple[str, str] - (status_string, html_body)
Raises:
- Returns 405 Method Not Allowed if the method handler is not implemented
This method is called automatically by Wiverno and typically doesn't need to be called directly.
Request Dispatching¶
BaseView automatically routes requests to methods based on request.method:
class APIView(BaseView):
def get(self, request):
return "200 OK", "GET response"
def post(self, request):
return "201 CREATED", "POST response"
# When request.method == "GET", get() is called
# When request.method == "POST", post() is called
# When request.method == "PUT", 405 is returned (not implemented)
Error Handling¶
If the HTTP method is not implemented, BaseView automatically returns a 405 Method Not Allowed response:
class GetOnlyView(BaseView):
def get(self, request):
return "200 OK", "Data"
# PUT, POST, DELETE not implemented
# POST request will return 405
view = GetOnlyView()
request.method = "POST"
status, body = view(request)
# status == "405 METHOD NOT ALLOWED"
Registration with Application¶
Using Decorator¶
Register a class-based view using the @app.route() or HTTP method decorators:
from wiverno.main import Wiverno
from wiverno.views.base_views import BaseView
app = Wiverno()
class UserView(BaseView):
def get(self, request):
return "200 OK", "Users"
def post(self, request):
return "201 CREATED", "User created"
# Register the instantiated view
app.route("/users")(UserView())
With Router¶
Use class-based views with routers:
from wiverno.core.routing.router import Router
router = Router()
class ItemView(BaseView):
def get(self, request):
return "200 OK", "Items"
router.route("/items")(ItemView())
app.include_router(router, prefix="/api")
Usage Examples¶
Simple GET and POST Handler¶
from wiverno.views.base_views import BaseView
from wiverno.core.requests import Request
class ContactView(BaseView):
def get(self, request: Request) -> tuple[str, str]:
return "200 OK", """
<form method="POST">
<input type="text" name="message">
<button>Send</button>
</form>
"""
def post(self, request: Request) -> tuple[str, str]:
message = request.data.get('message')
return "200 OK", f"Message received: {message}"
# Register
app.route("/contact")(ContactView())
REST API Endpoint¶
class ArticleView(BaseView):
def get(self, request: Request) -> tuple[str, str]:
# Get all articles
return "200 OK", '[{"id": 1, "title": "First"}]'
def post(self, request: Request) -> tuple[str, str]:
# Create new article
data = request.data
title = data.get('title')
return "201 CREATED", f'{{"title": "{title}"}}'
def put(self, request: Request) -> tuple[str, str]:
# Update article
return "200 OK", '{"updated": true}'
def delete(self, request: Request) -> tuple[str, str]:
# Delete article
return "204 NO CONTENT", ""
app.route("/articles")(ArticleView())
Combining with Templates¶
from wiverno.templating.templator import Templator
class ProfileView(BaseView):
def __init__(self):
self.templator = Templator()
def get(self, request: Request) -> tuple[str, str]:
user_id = request.query_params.get('id')
html = self.templator.render("profile.html", {
"user_id": user_id
})
return "200 OK", html
def post(self, request: Request) -> tuple[str, str]:
# Update profile
return "200 OK", "Profile updated"
app.route("/profile")(ProfileView())
API Validation¶
import json
class DataAPIView(BaseView):
def get(self, request: Request) -> tuple[str, str]:
return "200 OK", json.dumps({"status": "ok"})
def post(self, request: Request) -> tuple[str, str]:
# Validate request data
required_fields = {'name', 'email'}
provided_fields = set(request.data.keys())
if not required_fields.issubset(provided_fields):
return "400 BAD REQUEST", "Missing required fields"
# Process data
return "201 CREATED", json.dumps({"created": True})
def put(self, request: Request) -> tuple[str, str]:
if not request.data:
return "400 BAD REQUEST", "Empty body"
return "200 OK", json.dumps({"updated": True})
app.route("/api/data")(DataAPIView())
Using Class State¶
class CacheView(BaseView):
def __init__(self):
self.cache = {}
def get(self, request: Request) -> tuple[str, str]:
key = request.query_params.get('key')
if key in self.cache:
return "200 OK", self.cache[key]
return "404 NOT FOUND", "Not found"
def post(self, request: Request) -> tuple[str, str]:
key = request.data.get('key')
value = request.data.get('value')
self.cache[key] = value
return "201 CREATED", "Cached"
cache_view = CacheView()
app.route("/cache")(cache_view)
Multi-Action View¶
class AdminDashboardView(BaseView):
def get(self, request: Request) -> tuple[str, str]:
action = request.query_params.get('action', 'overview')
if action == 'overview':
return "200 OK", "Dashboard overview"
elif action == 'users':
return "200 OK", "User management"
elif action == 'settings':
return "200 OK", "Settings"
else:
return "400 BAD REQUEST", "Invalid action"
def post(self, request: Request) -> tuple[str, str]:
action = request.data.get('action')
if action == 'save_settings':
return "200 OK", "Settings saved"
elif action == 'create_user':
return "201 CREATED", "User created"
else:
return "400 BAD REQUEST", "Invalid action"
app.route("/admin")(AdminDashboardView())
Comparison: Function-Based vs Class-Based¶
Function-Based View¶
@app.route("/items", methods=["GET", "POST"])
def items_view(request):
if request.method == "GET":
return "200 OK", "Items list"
elif request.method == "POST":
return "201 CREATED", "Item created"
Class-Based View¶
class ItemsView(BaseView):
def get(self, request):
return "200 OK", "Items list"
def post(self, request):
return "201 CREATED", "Item created"
app.route("/items")(ItemsView())
Class-based views are cleaner when handling multiple HTTP methods for the same resource.
See Also¶
- Application - Wiverno application class
- Request - Request handling
- Router - URL routing