Database Models
ClassQuiz uses PostgreSQL as its primary database with Ormar as the ORM. Ormar is built on SQLAlchemy Core and Pydantic, providing async database operations with full type safety. All models are defined inclassquiz/db/models.py.
Core Models
User
The main user account model. Table:users
Fields:
- Has many
Quiz - Has many
UserSession - Has many
FidoCredentials - Has many
ApiKey - Has many
GameResults - Has many
QuizTivity - Has many
StorageItem - Has many
Controller - Has many
Rating
passwordis nullable for OAuth-only accountsavataris stored as binary and represented as base64 stringbackup_codeis a 64-character hex string for account recoverytotp_secretis used for 2FA (Time-based One-Time Password)storage_usedtracks total bytes used by user’s uploaded files
UserSession
Tracks active user sessions for authentication. Table:user_sessions
Fields:
session_keyis used as JWT or session identifier- Sessions are tracked by IP and user agent for security
last_seenupdated on each request- Cascade deleted when user is deleted
FidoCredentials
Stores WebAuthn/FIDO credentials for passwordless authentication. Table:fido_credentials
Fields:
- Supports hardware security keys (YubiKey, etc.)
sign_countprevents replay attacks- Multiple credentials per user supported
ApiKey
API keys for programmatic access. Table:api_keys
Fields:
- 48-character random key
- Used for API authentication
- Key itself is primary key
Quiz Models
Quiz
The main quiz/questionnaire model. Table:quiz
Fields:
- Belongs to
User(viauser_id) - Has many
GameResults - Has many
Rating - Many-to-many with
StorageItem
questionsstored as JSON array- Public quizzes visible in community
- Import tracking for Kahoot compatibility
- Engagement metrics (likes, plays, views)
mod_ratingset by moderators
QuizQuestion (Pydantic Model)
Stored within Quiz’squestions JSON field.
GameResults
Stores completed game session results. Table:game_results
Fields:
- Belongs to
Quiz - Belongs to
User(game host)
- Denormalized: stores quiz title, description, questions
answerscontains all player responsesplayer_scoresmaps username to final scorecustom_field_datafor additional player metadata (class, student ID, etc.)
Rating
User ratings for quizzes (like/dislike). Table:rating
Fields:
- One rating per user per quiz
positive= True for like, False for dislike- Updates quiz’s
likes/dislikescounters
Game Session Models (Redis-based)
These are Pydantic models stored in Redis during active games.PlayGame
Active game session data.game:{game_pin}
Notes:
- Expires after 2 hours by default
current_questionis -1 before game startsquestion_showindicates if question is visible to players
GameSession
Game session metadata.game_session:{game_pin}
GamePlayer
Player information in active game.game_session:{game_pin}:players- Set of all playersgame_session:{game_pin}:players:{username}- Socket ID for specific playergame_session:{game_pin}:player_scores- Hash of username → score
AnswerDataList
List of answers for a question.game_session:{game_pin}:{question_index}
QuizTivity Models
“QuizTivity” is an interactive activity builder feature.QuizTivity
Table:quiztivitys
Fields:
- Belongs to
User - Has many
QuizTivityShare - Many-to-many with
StorageItem
pagesstored as JSON- Pages defined in
classquiz/db/quiztivity.py
QuizTivityShare
Shared/public links for QuizTivity. Table:quiztivityshares
Fields:
- Optional expiration
- Share name for organization
Storage Models
StorageItem
Uploaded files (images, videos). Table:storage_items
Fields:
- Belongs to
User(SET_NULL on delete) - Many-to-many with
Quiz - Many-to-many with
QuizTivity
hashis MD5 hash for deduplication (16 bytes)storage_pathused for local storage backendserverfor S3 bucket identifier- Soft delete with
deleted_at thumbhashfor blur placeholdersizetracked for storage quota enforcement
Controller Models
For remote game control (e.g., mobile device controlling presentation).Controller
Table:controller
Fields:
secret_keyfor authentication- Track version for updates
- Device name and player name
Instance Data
Singleton table for instance-level configuration.InstanceData
Table:instance_data
Fields:
- Typically contains only one row
- Used for instance identification
Database Configuration
Fromclassquiz/config.py:
classquiz/db/__init__.py:
Migrations
ClassQuiz uses Alembic for database migrations. Generate migration:alembic/versions/
Indexes and Performance
Key Indexes
users.email- UNIQUE index for loginusers.username- UNIQUE indexuser_sessions.session_key- UNIQUE index for session lookupquiz.user_id- Foreign key indexgame_results.quiz- Foreign key indexgame_results.user- Foreign key index
Query Optimization
- Ormar uses async queries (via
asyncpg) - Use
.select_related()for foreign keys - Use
.prefetch_related()for reverse relations
Data Validation
All models use Pydantic validation:Storage Quota System
- Each user has
storage_usedfield - Incremented on file upload
- Checked before allowing new uploads
- Decremented on file deletion
Redis Data Patterns
While primary data is in PostgreSQL, active games use Redis:Best Practices
Creating Models
Querying
Updating
Deleting
Transactions
Schema Diagram
See Also
- Architecture Overview - System architecture
- Socket.IO Events - Real-time communication
- Ormar Documentation - ORM reference