REST Schemas
Purpose: Define Pydantic-based data models that map to REST API responses, providing type-safe field access and a Django-like
.objectsmanager interface.
Why REST Schemas?
External API responses need consistent parsing and validation. The REST Schema system provides:
- Pydantic
BaseModelintegration for automatic validation - Type-safe field definitions matching API response structure
- Django model-like
.objectsmanager access pattern - Optional bridge to Django models via
DjangoModelRestSchema - Full Pydantic feature support (validators, computed fields, etc.)
Quick Start
1. Create a SchemaSet First
The Schema requires a SchemaSet, so create that first (see SchemaSets):
from django_spire.contrib.rest import RestSchemaSet
class PirateRestSchemaSet(RestSchemaSet['PirateRestSchema']):
# ... implementation (see SchemaSets documentation)
pass
2. Define the Schema
from django_spire.contrib.rest import RestSchema
from your_app.rest.schemaset import PirateRestSchemaSet
class PirateRestSchema(RestSchema):
id: int
firstName: str
lastName: str
email: str
username: str
objects = PirateRestSchemaSet.as_manager()
3. Query Using the Schema
from your_app.rest.schema import PirateRestSchema
# Access data through the .objects manager
pirates = PirateRestSchema.objects.all()
first_pirate = PirateRestSchema.objects.first()
Core Concepts
RestSchema
Abstract base class combining Pydantic's BaseModel with a Django-like .objects manager.
| Class Attribute | Type | Description |
|---|---|---|
objects |
RestSchemaSet |
Manager instance for QuerySet-like operations |
Subclasses must:
- Define Pydantic field annotations matching the API response
- Assign a SchemaSet instance to
objectsusing.as_manager()
DjangoModelRestSchema
Optional bridge class for schemas that correspond to Django models.
| Abstract Method | Description |
|---|---|
from_django_model(cls, model) |
Create schema instance from a Django model instance |
to_django_model(self) |
Convert schema instance to a Django model instance |
Main Operations
Defining Schema Fields
Schema fields use standard Pydantic type annotations:
from typing import Optional
from datetime import datetime
from django_spire.contrib.rest import RestSchema
from your_app.rest.schemaset import OrderRestSchemaSet
class OrderRestSchema(RestSchema):
id: int
order_number: str
total: float
status: str
created_at: datetime
notes: Optional[str] = None
objects = OrderRestSchemaSet.as_manager()
Using the Objects Manager
The .objects attribute provides a SchemaSet bound to this schema class:
from your_app.rest.schema import PirateRestSchema
# All pirates
all_pirates = PirateRestSchema.objects.all()
# Filtered pirates
filtered = PirateRestSchema.objects.filter(firstName='Jack')
# Chained operations
result = (
PirateRestSchema.objects
.filter(lambda p: p.id > 5)
.order_by('lastName')
.limit(10)
)
Nested Schemas
For APIs returning nested objects, define nested Pydantic models:
from pydantic import BaseModel
from django_spire.contrib.rest import RestSchema
from your_app.rest.schemaset import ShipRestSchemaSet
class CaptainInfo(BaseModel):
name: str
rank: str
class ShipRestSchema(RestSchema):
id: int
name: str
captain: CaptainInfo
objects = ShipRestSchemaSet.as_manager()
Access nested fields with dot notation:
Filter using double-underscore syntax:
Bridging to Django Models
Use DjangoModelRestSchema when you need to sync API data with local Django models:
from typing import Self
from django_spire.contrib.rest import DjangoModelRestSchema
from your_app.models import Pirate
from your_app.rest.schemaset import PirateRestSchemaSet
class PirateRestSchema(DjangoModelRestSchema):
id: int
firstName: str
lastName: str
email: str
username: str
objects = PirateRestSchemaSet.as_manager()
@classmethod
def from_django_model(cls, model: Pirate) -> Self:
return cls(
id=model.pk,
firstName=model.first_name,
lastName=model.last_name,
email=model.email,
username=model.username,
)
def to_django_model(self) -> Pirate:
return Pirate(
first_name=self.firstName,
last_name=self.lastName,
email=self.email,
username=self.username,
)
Using Pydantic Features
Since RestSchema extends Pydantic's BaseModel, you can use all Pydantic features:
from pydantic import field_validator, computed_field
from django_spire.contrib.rest import RestSchema
from your_app.rest.schemaset import PirateRestSchemaSet
class PirateRestSchema(RestSchema):
id: int
firstName: str
lastName: str
email: str
objects = PirateRestSchemaSet.as_manager()
@computed_field
@property
def full_name(self) -> str:
return f'{self.firstName} {self.lastName}'
@field_validator('email')
@classmethod
def validate_email(cls, v: str) -> str:
if '@' not in v:
raise ValueError('Invalid email format')
return v.lower()
Common Patterns
Schema with Optional Fields
from typing import Optional
from django_spire.contrib.rest import RestSchema
from your_app.rest.schemaset import CrewMemberRestSchemaSet
class CrewMemberRestSchema(RestSchema):
id: int
name: str
rank: Optional[str] = None
years_of_service: Optional[int] = None
objects = CrewMemberRestSchemaSet.as_manager()