Models and Pydantic validation
SparqlModel entities are Pydantic v2 models with RDF metadata. This guide covers validation on write and read, Field constraints, and how that relates to TripleModel underneath.
For session and persistence semantics see Sessions and stores. For the full ORM picture see SparqlModel ORM guide.
Why Pydantic
If you use FastAPI or SQLModel, you already know the pattern: define a class with typed fields, let Pydantic validate input, and work with ordinary Python objects in application code.
SparqlModel applies that to RDF:
Catch
name=123or missing required fields beforesession.put.Catch graph data that does not match your annotations when hydrating from a store.
Generate JSON Schema from models for OpenAPI when using FastAPI integration.
TripleModel (required dependency) is also Pydantic-based. SPARQLModel subclasses TripleModel (Option A, 0.4+) — one class for app code, mapping, and queries. You rarely import triplemodel in app code unless you need stateless file I/O without a session.
Define a model
from sparqlmodel import Field, IRI, Relationship, SPARQLModel
class Organization(SPARQLModel):
rdf_type = "schema:Organization"
__prefixes__ = {"schema": "https://schema.org/"}
id: IRI
name: str = Field("schema:name")
class Person(SPARQLModel):
rdf_type = "schema:Person"
__prefixes__ = {"schema": "https://schema.org/"}
id: IRI
name: str = Field("schema:name")
works_for: Organization | None = Relationship(
"schema:worksFor", model=Organization
)
Piece |
Role |
|---|---|
|
RDF class IRI (compact or absolute); maps to TripleModel |
|
CURIE → namespace map for predicates and types |
|
Scalar mapped to a predicate ( |
|
Link to another |
SPARQLModel uses model_config = ConfigDict(extra="forbid"), so extra keys in input data are rejected.
Validation on write
Validation runs when you construct an instance:
Person(id=IRI("urn:p:1"), name="Ada") # ok
Person(id=IRI("urn:p:2"), name=123) # pydantic.ValidationError
When you session.put(person), the session serializes an already-validated instance:
0.4+:
sync_to_graph(person, …)on theSPARQLModelinstance (aTripleModel).0.4.0+:
session.put→rdf_bridge.model_to_graphonSPARQLModelinstances (subclassTripleModel).
Validation on read
session.get and query hydration load from the store graph via TripleModel from_graph, then SPARQLModel.model_validate (with SparqlModel depth for relationships).
If stored triples do not match your field types (for example a literal where you declared int), hydration raises HydrationError wrapping Pydantic’s ValidationError.
Configuration mistakes (for example hydration cycles) raise ConfigurationError instead. See Troubleshooting.
TripleModel’s from_graph(..., validate_type=True) also checks that subjects have the expected rdf:type before scalars are applied.
Pydantic Field kwargs
sparqlmodel.Field and Relationship forward extra keyword arguments to pydantic.Field:
class Product(SPARQLModel):
rdf_type = "schema:Product"
__prefixes__ = {"schema": "https://schema.org/"}
id: IRI
name: str = Field("schema:name", min_length=1, description="Display name")
stock: int = Field("schema:inventoryLevel", ge=0)
Use standard Pydantic constraints on scalar fields. Relationship fields support the same kwargs where they apply to the declared annotation (for example optional defaults).
Richer RDF modeling (0.13+)
Requires triplemodel>=0.12.0 (SparqlModel 0.13.0).
Feature |
Usage |
|---|---|
Multi-valued scalars |
|
Multi-ref links |
|
Language tags |
|
Typed literals |
|
Inverse / paired fields |
|
Ontology hints |
|
Import ResourceRef, LangString, MultiLangString, and TypedLiteral from sparqlmodel (re-exported from TripleModel). Prefer put when shrinking a set[ResourceRef] so orphan cleanup removes dropped targets only.
What Pydantic does not cover (yet)
Concern |
Today |
Planned |
|---|---|---|
App-level types and constraints |
Pydantic on |
— |
RDF type of subject on load |
TripleModel |
— |
Multi-valued predicates ( |
Full round-trip via TripleModel 0.12+ |
— |
Language tags ( |
|
— |
Graph shape rules (cardinality, domains) |
Not enforced |
SHACL on |
Pydantic validates Python values against your model. It does not replace SHACL or OWL reasoning for graph-level rules.
TripleModel integration (Option A)
Target (0.4+): SPARQLModel is a TripleModel. Field / Relationship build rdf_field / Predicate and nested class Rdf at class creation — no dynamic shadow classes.
Write:
session.put→ cascade policy →sync_to_graphon your instance.Read:
from_graphon your class → depth hydration → identity map.
0.4.0+: one model class; no _triple.py adapter.
Application code should stay on SPARQLModel, Field, and Relationship. For stateless file parse/serialize or ETL without a session, you may import TripleModel directly — see SparqlModel ORM guide.