A jinja2 view template helping function for FastAPI.
Project description
fastapi-view
A lightweight, flexible Jinja2 template rendering library for FastAPI applications, with built-in support for Inertia.js and Vite integration.
Features
- Simple View Rendering: Minimal boilerplate for rendering Jinja2 templates in FastAPI routes
- Inertia.js Support: FastAPI Inertia.js adapter for building modern monolithic applications
- Vite Integration: Seamless Vite asset management with HMR support in development
- Flexible Configuration: Environment-based settings using Pydantic
Installation
pip install fastapi-view
Or using uv:
uv add fastapi-view
Quick Start
Basic View Rendering
from fastapi import FastAPI
from fastapi_view import ViewDepends
app = FastAPI()
@app.get("/")
def index(view: ViewDepends):
return view.render("index", {"message": "Hello World"})
Set the templates directory via environment variable:
export FV_TEMPLATES_PATH=templates
Inertia.js Integration
from fastapi import FastAPI
from fastapi_view.inertia import InertiaDepends
app = FastAPI()
@app.get("/dashboard")
def dashboard(inertia: InertiaDepends):
return inertia.render("Dashboard/Index", props={
"user": {"name": "John Doe", "email": "john@example.com"}
})
Configure Inertia via environment variables:
export FV_INERTIA_ROOT_TEMPLATE=app.html
export FV_INERTIA_ASSETS_VERSION=v1
Vite Asset Management
In your Jinja2 template:
<!DOCTYPE html>
<html>
<head>
{{ vite_hmr_client() | safe }}
{{ vite_asset('resources/js/app.ts') | safe }}
</head>
<body>
<div id="app"></div>
</body>
</html>
Configure Vite settings:
export FV_VITE_DEV_MODE=true
export FV_VITE_DEV_SERVER_URL=http://localhost:5173
export FV_VITE_MANIFEST_PATH=public/build/manifest.json
Configuration
fastapi-view uses Pydantic settings for configuration. All settings can be configured via environment variables with the FV_ prefix.
View Settings
| Environment Variable | Description | Required | Default |
|---|---|---|---|
FV_TEMPLATES_PATH |
Path to Jinja2 templates directory | Yes | - |
Inertia Settings
| Environment Variable | Description | Required | Default |
|---|---|---|---|
FV_INERTIA_ROOT_TEMPLATE |
Root template for Inertia responses | No | app.html |
FV_INERTIA_ASSETS_VERSION |
Asset versioning for cache busting | No | None |
Vite Settings
| Environment Variable | Description | Required | Default |
|---|---|---|---|
FV_VITE_DEV_MODE |
Enable development mode with HMR | No | False |
FV_VITE_DEV_SERVER_PROTOCOL |
Protocol for Vite dev server (http/https) | No | http |
FV_VITE_DEV_SERVER_HOST |
Host for Vite dev server | No | localhost |
FV_VITE_DEV_SERVER_PORT |
Port for Vite dev server | No | 5173 |
FV_VITE_WS_CLIENT_PATH |
WebSocket client path for HMR | No | @vite/client |
FV_VITE_MANIFEST_PATH |
Path to Vite manifest file | No | dist/.vite/manifest.json |
FV_VITE_DIST_PATH |
Path to build output directory | No | dist |
FV_VITE_DIST_URI_PREFIX |
URI prefix for serving static assets | Yes (in production mode) | None |
FV_VITE_STATIC_URL |
Base URL for static assets (alternative to uri prefix) | Yes (in production mode) | None |
Note: In production mode (FV_VITE_DEV_MODE=False), either FV_VITE_STATIC_URL or FV_VITE_DIST_URI_PREFIX must be configured.
Advanced Usage
Shared Inertia Props
Share data within a request by calling share() on the Inertia instance:
from fastapi_view.inertia import InertiaDepends
@app.get("/dashboard")
def dashboard(inertia: InertiaDepends):
# Share props for this request
inertia.share("app_name", "My Application")
inertia.share("user", get_current_user())
return inertia.render("Dashboard/Index", props={"stats": get_stats()})
For sharing data across all routes, use a dependency or middleware:
from fastapi import Depends
def with_shared_props(inertia: InertiaDepends):
inertia.share("app_name", "My Application")
inertia.share("version", "1.0.0")
return inertia
@app.get("/dashboard")
def dashboard(inertia: InertiaDepends = Depends(with_shared_props)):
return inertia.render("Dashboard/Index", props={"stats": get_stats()})
Optional Props
Use optional props for lazy loading data:
@app.get("/users")
def users(inertia: InertiaDepends):
return inertia.render("Users/Index", props={
"users": lambda: fetch_users(), # Always evaluated
"metrics": inertia.optional(lambda: fetch_metrics()) # Only on partial reload
})
Flash Messages
Flash messages for one-time notifications (requires SessionMiddleware):
from starlette.middleware.sessions import SessionMiddleware
app.add_middleware(SessionMiddleware, secret_key="your-secret-key")
@app.post("/login")
def login(inertia: InertiaDepends):
# ... authentication logic ...
inertia.flash("success", "Login successful!")
return inertia.render("Dashboard")
Flash messages are available on the frontend under the flash prop:
<script setup>
import { usePage } from '@inertiajs/vue3'
const page = usePage()
const flash = page.props.flash
// Access flash messages
if (flash.success) {
console.log(flash.success)
}
if (flash.error) {
console.log(flash.error)
}
</script>
Deferred Props
Use deferred props to load expensive data after the initial page render, improving perceived performance:
@app.get("/dashboard")
def dashboard(inertia: InertiaDepends):
return inertia.render("Dashboard/Index", props={
# Fast data loaded immediately
"quick_stats": get_quick_stats(),
# Slow data deferred - loads after initial page render
"statistics": inertia.defer(lambda: get_statistics(), group="analytics"),
"recent_activities": inertia.defer(lambda: fetch_activities(), group="analytics"),
# Another deferred group for separate loading
"chart_data": inertia.defer(lambda: get_chart_data(), group="charts")
})
On the frontend, deferred props will be undefined initially, then populated once loaded:
<template>
<!-- Show skeleton while loading -->
<div v-if="statistics">
<p>Total Users: {{ statistics.total_users }}</p>
</div>
<div v-else class="animate-pulse">
<div class="h-4 bg-gray-300 rounded"></div>
</div>
</template>
<script setup>
defineProps(['statistics']) // Will be undefined, then populated
</script>
Benefits:
- Faster initial page load
- Better user experience with progressive data loading
- Group related deferred props for efficient batching
Merge Props
Use merge props to combine new data with existing client-side data during partial reloads (perfect for infinite scroll, "load more" features):
@app.get("/posts")
def posts(inertia: InertiaDepends, page: int = 1):
per_page = 10
offset = (page - 1) * per_page
posts = fetch_posts(offset, per_page)
return inertia.render("Posts/Index", props={
"posts": inertia.merge(lambda: posts),
"pagination": {
"current_page": page,
"has_more": has_more_posts(page, per_page)
}
})
On the frontend, use Inertia's partial reload to append new data:
<template>
<div>
<div v-for="post in posts" :key="post.id">
<h3>{{ post.title }}</h3>
</div>
<button v-if="pagination.has_more" @click="loadMore">
Load More
</button>
</div>
</template>
<script setup>
import { router } from '@inertiajs/vue3'
const props = defineProps(['posts', 'pagination'])
function loadMore() {
router.reload({
data: { page: props.pagination.current_page + 1 },
only: ['posts', 'pagination']
})
}
</script>
Advanced merge options:
# Deep merge for nested objects
inertia.merge(lambda: data).deep_merge()
# Prepend instead of append
inertia.merge(lambda: posts).prepend()
# Append/prepend at specific paths
inertia.merge(lambda: data).append(paths=["items", "results"])
# Prevent duplicates by matching on a field
inertia.merge(lambda: posts).append(match_on="id")
Benefits:
- Efficient "load more" / infinite scroll implementations
- Reduced data transfer on partial reloads
- Automatic client-side data merging
Custom Response Configuration
@app.get("/custom")
def custom_view(view: ViewDepends):
return view.render(
"custom",
context={"data": "value"},
status_code=201,
headers={"X-Custom-Header": "value"}
)
Complete Example
Check out the full Inertia.js example application in the examples/inertia directory, which demonstrates:
- User authentication flow
- CRUD operations with Inertia
- Vite + Vue 3 + TypeScript frontend
- Session management
- Form handling
To run the example:
cd examples/inertia
cp .env.example .env
uv sync
bun install
bun run build
uv run uvicorn app.main:app --reload
Development
Setup
git clone https://github.com/turisesonia/fastapi-view.git
cd fastapi-view
uv sync
Running Tests
uv run pytest
Code Formatting
uvx ruff format
uvx ruff check --fix
Requirements
- Python 3.10+
- FastAPI 0.70+
- Jinja2 3.0+
- Pydantic Settings 2.0+
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Links
Acknowledgments
- Built with FastAPI
- Template rendering powered by Jinja2
- Inspired by Laravel's view system and Inertia.js
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_view-0.6.3.tar.gz.
File metadata
- Download URL: fastapi_view-0.6.3.tar.gz
- Upload date:
- Size: 209.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61d8fcdf56df9f3a380bb9e3668d4e366d2e45f0e6d2b5f6e196d09d248a0190
|
|
| MD5 |
993e43a1ff14a8860c43489be6fcb290
|
|
| BLAKE2b-256 |
2531d83585668ed9b3223187af8cd105d60d185995239591a16d5fe2725352cf
|
File details
Details for the file fastapi_view-0.6.3-py3-none-any.whl.
File metadata
- Download URL: fastapi_view-0.6.3-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c4599152a46fd443717548f5a7693dadf17a839e84b2d9a5a3a672968309c05
|
|
| MD5 |
8d892356dc5557f7a2119f77716b0cce
|
|
| BLAKE2b-256 |
bfa916c50a0f8a6caf7ff005c21b39b58f55678c3d6f2be361cbf31f253cd275
|