Skip to main content
Models are the foundation of every VeloIQ application. Define a model once in Python and the framework automatically generates a REST API, an SQLAdmin back-office view, and TypeScript schemas for the React frontend — no repetition required.

Base classes

VeloIQ provides three base classes. Choose the one that matches your storage requirements; all three are imported directly from veloiq_framework.

FrameworkModel

FrameworkModel is the minimal base. It provides a single auto-increment integer primary key named id and nothing else — no audit columns, no extra metadata. Use it when you want the UI to show only the fields you declare.

TimestampedModel

TimestampedModel extends FrameworkModel with automatic created_at and updated_at columns. The code generator appends these two fields after all fields you declare, so they appear last in every list, form, and detail view.
Use TimestampedModel as your default. Audit timestamps are almost always useful, and you can always switch to FrameworkModel later if a specific model genuinely doesn’t need them.

StandardModel

StandardModel is for applications that must stay compatible with a CubicWeb database. It uses eid as the Python attribute name, mapped to the cw_eid physical column, and follows cw_ column naming conventions. New greenfield applications should use FrameworkModel or TimestampedModel instead.

Field types

Standard Python and SQLModel types work directly on all base classes. Use Optional[T] for nullable columns and set default=None or any other default value as needed.

Relations with jm_relationship()

Use jm_relationship() to declare SQLModel relationships. The function is a thin wrapper around SQLModel’s Relationship that attaches cardinality metadata — the frontend reads this to render required/optional indicators and pagination hints.

One-to-many

Declare the collection on the parent and the scalar reference on the child, each pointing back at the other with back_populates.

Self-referential

A model can reference itself to represent hierarchies such as tasks with subtasks. Self-referential relationships automatically trigger Miller column rendering in the frontend — clicking a row drills into its children in an adjacent column.

jm_relationship() parameters

Field options with veloiq_field()

Use veloiq_field() in place of a plain Field() to add per-role read and write restrictions to individual columns. For example, to allow only Admins to read or change an employee’s salary:
veloiq_field() accepts all the same keyword arguments as pydantic.Field. See Access Control for the full details on read_roles, write_roles, and how field-level restrictions interact with the broader RBAC system.

Code generation

After defining or changing your models, run veloiq generate from the backend directory:
This writes two files for each module:
  • backend/app/modules/{module}/api.py — CRUD REST endpoints (do not edit)
  • frontend/src/pages/{module}/{module}Schema.gen.ts — TypeScript field definitions (do not edit)
Re-run veloiq generate every time you add, rename, or remove a field or model.

Modules

Understand how modules are structured and auto-loaded

Access Control

Apply RBAC and ReBAC to your models and fields