Ir para o conteúdo

Models

SQLAlchemy models with Django-style conveniences.

Basic Model

from strider import Model, Field
from sqlalchemy.orm import Mapped

class Post(Model):
    __tablename__ = "posts"
    
    id: Mapped[int] = Field.pk()
    title: Mapped[str] = Field.string(max_length=200)
    content: Mapped[str] = Field.text()
    views: Mapped[int] = Field.integer(default=0)
    published: Mapped[bool] = Field.boolean(default=False)
    created_at: Mapped[datetime] = Field.datetime(auto_now_add=True)

Field Types

Field SQL Type Example
Field.pk() INTEGER PRIMARY KEY id: Mapped[int] = Field.pk()
Field.uuid_pk() UUID PRIMARY KEY id: Mapped[UUID] = Field.uuid_pk()
Field.string(max_length) VARCHAR name: Mapped[str] = Field.string(100)
Field.text() TEXT bio: Mapped[str] = Field.text()
Field.integer() INTEGER age: Mapped[int] = Field.integer()
Field.float_() FLOAT price: Mapped[float] = Field.float_()
Field.boolean() BOOLEAN active: Mapped[bool] = Field.boolean()
Field.datetime() TIMESTAMP created: Mapped[datetime] = Field.datetime()
Field.date() DATE birth: Mapped[date] = Field.date()
Field.json() JSON/JSONB meta: Mapped[dict] = Field.json()

Field Options

Field.string(
    max_length=200,      # VARCHAR length
    nullable=True,       # Allow NULL
    default="draft",     # Python default
    index=True,          # Create index
    unique=True,         # Unique constraint
)

Auto Timestamps

class Post(Model):
    __tablename__ = "posts"
    
    id: Mapped[int] = Field.pk()
    created_at: Mapped[datetime] = Field.datetime(auto_now_add=True)  # Set on create
    updated_at: Mapped[datetime] = Field.datetime(auto_now=True)      # Set on update

Relationships

from strider.relations import Rel

class Post(Model):
    __tablename__ = "posts"
    
    id: Mapped[int] = Field.pk()
    author_id: Mapped[int] = Field.fk("users.id")
    
    # Relationship (for ORM access)
    author: Mapped["User"] = Rel.many_to_one("User", back_populates="posts")

class User(Model):
    __tablename__ = "users"
    
    id: Mapped[int] = Field.pk()
    posts: Mapped[list["Post"]] = Rel.one_to_many("Post", back_populates="author")

Relationship Types

# Many-to-One (FK on this model)
author: Mapped["User"] = Rel.many_to_one("User")

# One-to-Many (FK on other model)
posts: Mapped[list["Post"]] = Rel.one_to_many("Post")

# Many-to-Many
tags: Mapped[list["Tag"]] = Rel.many_to_many("Tag", secondary="post_tags")

User Model

Extend AbstractUser for authentication:

from strider.auth import AbstractUser, PermissionsMixin
from strider import Field
from sqlalchemy.orm import Mapped

class User(AbstractUser, PermissionsMixin):
    __tablename__ = "users"
    
    # AbstractUser provides: id, email, password, is_active, is_staff, is_superuser
    # PermissionsMixin provides: groups, user_permissions
    
    # Add custom fields
    first_name: Mapped[str | None] = Field.string(max_length=100, nullable=True)
    avatar_url: Mapped[str | None] = Field.string(max_length=500, nullable=True)

Model Discovery

All models must be imported in src/apps/models.py:

# src/apps/models.py
from src.apps.users.models import User  # noqa
from src.apps.posts.models import Post  # noqa

This ensures models are registered before migrations run.

QuerySet (Django-style)

# Get all
posts = await Post.objects.all()

# Filter
posts = await Post.objects.filter(published=True).all()

# Get one
post = await Post.objects.get(id=1)

# First
post = await Post.objects.filter(author_id=1).first()

# Count
count = await Post.objects.filter(published=True).count()

# Order
posts = await Post.objects.order_by("-created_at").all()

# Limit
posts = await Post.objects.limit(10).all()

See QuerySets for full reference.

Next