Choices¶
Django-style TextChoices and IntegerChoices.
Important: Use TextChoices/IntegerChoices instead of Python Enum.
TextChoices¶
For string values.
from strider.choices import TextChoices
class Status(TextChoices):
DRAFT = "draft", "Draft"
PUBLISHED = "published", "Published"
ARCHIVED = "archived", "Archived"
IntegerChoices¶
For integer values.
from strider.choices import IntegerChoices
class Priority(IntegerChoices):
LOW = 1, "Low Priority"
MEDIUM = 2, "Medium Priority"
HIGH = 3, "High Priority"
CRITICAL = 4, "Critical"
Usage in Models¶
from strider import Model, Field
from sqlalchemy.orm import Mapped
class Status(TextChoices):
DRAFT = "draft", "Draft"
PUBLISHED = "published", "Published"
class Post(Model):
__tablename__ = "posts"
status: Mapped[str] = Field.choice(Status, default=Status.DRAFT)
Native PostgreSQL ENUM¶
status: Mapped[str] = Field.choice(
Status,
default=Status.DRAFT,
use_native_enum=True # Uses PostgreSQL ENUM type
)
Accessing Values¶
# Value
Status.DRAFT.value # "draft"
Priority.HIGH.value # 3
# Label
Status.DRAFT.label # "Draft"
Priority.HIGH.label # "High Priority"
# All choices (for forms/API)
Status.choices # [("draft", "Draft"), ("published", "Published"), ...]
# All values
Status.values # ["draft", "published", "archived"]
# All labels
Status.labels # ["Draft", "Published", "Archived"]
# Max length (for database column)
Status.max_length # 9 (length of "published")
Lookup Methods¶
# Get by value
Status.from_value("draft") # Status.DRAFT
# Get label for value
Status.get_label("draft") # "Draft"
# Check if valid
Status.is_valid("draft") # True
Status.is_valid("invalid") # False
Comparison¶
Works with both enum members and raw values:
post.status == Status.PUBLISHED # True
post.status == "published" # True
post.priority == Priority.HIGH # True
post.priority == 3 # True
Built-in Choices¶
CommonStatus¶
from strider.choices import CommonStatus
CommonStatus.ACTIVE # "active"
CommonStatus.INACTIVE # "inactive"
CommonStatus.PENDING # "pending"
CommonStatus.SUSPENDED # "suspended"
PublishStatus¶
from strider.choices import PublishStatus
PublishStatus.DRAFT # "draft"
PublishStatus.PENDING_REVIEW # "pending_review"
PublishStatus.PUBLISHED # "published"
PublishStatus.ARCHIVED # "archived"
OrderStatus¶
from strider.choices import OrderStatus
OrderStatus.PENDING # "pending"
OrderStatus.PROCESSING # "processing"
OrderStatus.COMPLETED # "completed"
OrderStatus.CANCELLED # "cancelled"
OrderStatus.REFUNDED # "refunded"
PaymentStatus¶
from strider.choices import PaymentStatus
PaymentStatus.PENDING # "pending"
PaymentStatus.PROCESSING # "processing"
PaymentStatus.PAID # "paid"
PaymentStatus.FAILED # "failed"
PaymentStatus.REFUNDED # "refunded"
PaymentStatus.CANCELLED # "cancelled"
TaskPriority¶
from strider.choices import TaskPriority
TaskPriority.LOW # 1
TaskPriority.MEDIUM # 2
TaskPriority.HIGH # 3
TaskPriority.CRITICAL # 4
Weekday¶
from strider.choices import Weekday
Weekday.MONDAY # 1
Weekday.TUESDAY # 2
# ... through
Weekday.SUNDAY # 7
Month¶
from strider.choices import Month
Month.JANUARY # 1
Month.FEBRUARY # 2
# ... through
Month.DECEMBER # 12
Gender¶
from strider.choices import Gender
Gender.MALE # "M"
Gender.FEMALE # "F"
Gender.OTHER # "O"
Gender.NOT_INFORMED # "N"
Visibility¶
from strider.choices import Visibility
Visibility.PUBLIC # "public"
Visibility.PRIVATE # "private"
Visibility.UNLISTED # "unlisted"
Visibility.MEMBERS # "members"
Validation¶
In Serializers¶
from strider.serializers import InputSchema
from pydantic import field_validator
class PostInput(InputSchema):
status: str
@field_validator("status")
@classmethod
def validate_status(cls, v):
if not Status.is_valid(v):
raise ValueError(f"Invalid status. Must be one of: {Status.values}")
return v
With ChoiceValidator¶
from strider.validators import ChoiceValidator
validator = ChoiceValidator(choices=Status.values)
validator("draft") # OK
validator("invalid") # Raises ValidationError
Querying¶
# Filter by choice
posts = await Post.objects.using(db).filter(status=Status.PUBLISHED).all()
# Or by value
posts = await Post.objects.using(db).filter(status="published").all()
# Multiple values
posts = await Post.objects.using(db).filter(
status__in=[Status.DRAFT, Status.PUBLISHED]
).all()
OpenAPI Documentation¶
Choices are automatically documented in OpenAPI:
class PostInput(InputSchema):
status: Status # Shows enum values in Swagger
Custom Choices¶
from strider.choices import TextChoices, IntegerChoices
class TicketType(TextChoices):
BUG = "bug", "Bug Report"
FEATURE = "feature", "Feature Request"
SUPPORT = "support", "Support Request"
QUESTION = "question", "Question"
class SeverityLevel(IntegerChoices):
TRIVIAL = 1, "Trivial"
MINOR = 2, "Minor"
MAJOR = 3, "Major"
BLOCKER = 4, "Blocker"
Why Not Python Enum?¶
TextChoices/IntegerChoices provide:
- Labels — Human-readable names
.choices— Ready for forms/dropdowns.values— List of valid values.max_length— For database column sizing- Direct comparison — Works with raw values
- Django compatibility — Familiar API