Teams — serializers¶
Responsibilities¶
The serializers in the Teams app are responsible for:
- Converting Team and TeamMembership data into API responses
- Providing lightweight, frontend-friendly representations
- Enriching data with computed fields (e.g. roles, labels, membership context)
- Supporting structured write operations for team and membership management
- Normalizing how users are displayed across team-related endpoints
They are intentionally thin, with all business logic delegated to the service layer.
Main serializers¶
TeamListSerializer¶
Represents a team in list responses (e.g. “my teams”).
Fields
- id
- name
- org
- role — Current user’s role in this team (computed)
- membership_id — Current user’s membership ID (computed)
- is_primary — Whether this is the user’s primary team (computed)
- is_active
- created_at
Behavior
- Uses request.user from context
- Resolves membership via TeamMembership
- Enriches response with user-specific data
Relationships
- Reads from Team
- Queries TeamMembership
TeamDetailSerializer¶
Represents a team with aggregated data.
Fields
- id
- name
- org
- is_active
- created_at
- member_count — Active member count (computed)
Behavior
- Counts active memberships (TeamMembership)
- Used for detail views or admin-style endpoints
Relationships
- Reads from Team
- Aggregates TeamMembership
TeamCreateSerializer¶
Used for creating new teams.
Fields
- name
- is_active (optional, default: true)
Behavior - Validates name presence and trimming - No DB logic (handled in services)
TeamUpdateSerializer¶
Used for partial updates to teams.
Fields
- name (optional)
- is_active (optional)
Behavior - Requires at least one field - Validates name if provided
TeamMembershipPairSerializer¶
Lightweight serializer for mapping relationships.
Fields
- team_id
- user_id
Use cases - Efficient graph-like responses - Frontend joins / mapping structures - Avoids heavy nested serialization
Relationships
- Reads from TeamMembership
- Does not include nested objects
TeamMemberOptionSerializer¶
Represents a user as a selectable option in a team context.
Fields
- id — User ID
- label — Display name (computed)
- email
- role — Org-level role (from OrgMembership)
Behavior
- Generates a human-friendly label:
1. profile.display_name
2. full_name
3. email
4. fallback to username / ID
Relationships
- Reads from OrgMembership
- Accesses related User
TeamMemberSerializer¶
Represents a team member (replaces inline payloads).
Fields
- id
- user_id
- user_email
- user_username
- user_label — Computed display label
- role
- is_primary
- is_active
- joined_at
Behavior - Normalizes user display logic - Used in team member listing endpoints
Relationships
- Reads from TeamMembership
- Accesses related User
TeamMembershipListSerializer¶
Represents full membership rows with team + user context.
Fields
- id
- team_id
- team_name
- user_id
- user_email
- user_username
- user_label
- role
- is_primary
- is_active
- joined_at
Use cases - Admin views - Debugging / analytics endpoints - Rich membership listings
TeamMembershipCreateSerializer¶
Used for adding a user to a team.
Fields
- user_id
- role (optional, default: member)
- is_primary (optional, default: false)
- is_active (optional, default: true)
Behavior - Provides sensible defaults - Input validation only (no business logic)
TeamMembershipWriteSerializer¶
Generic update serializer for memberships.
Fields
- user_id
- role (optional)
- is_primary (optional)
- is_active (optional)
Behavior - Requires at least one field - Used for flexible updates
TeamMembershipRoleUpdateSerializer¶
Used for updating membership roles.
Fields
- role
Behavior
- Validates against allowed TeamMembership.Role values
TeamMembershipPrimaryUpdateSerializer¶
Used for setting a membership as primary.
Fields
- is_primary (must be true)
Behavior - Only allows promoting a membership to primary - Clearing primary handled separately in services
TeamMembershipStatusSerializer¶
Used for activating/deactivating memberships.
Fields
- is_active
Behavior - Boolean normalization only
Serializer relationships (diagram)¶
graph TD
TeamListSerializer --> Team
TeamListSerializer --> TeamMembership
TeamDetailSerializer --> Team
TeamDetailSerializer --> TeamMembership
TeamMembershipPairSerializer --> TeamMembership
TeamMemberSerializer --> TeamMembership
TeamMemberSerializer --> User
TeamMemberOptionSerializer --> OrgMembership
TeamMemberOptionSerializer --> User
TeamMembershipListSerializer --> TeamMembership
TeamMembershipListSerializer --> Team
TeamMembershipListSerializer --> User
OrgMembership --> User
TeamMembership --> User
TeamMembership --> Team
Key design notes¶
1. Read vs write separation¶
- Clear distinction between:
- Read serializers (list/detail)
- Write serializers (create/update)
- Improves clarity and maintainability
2. Context-aware serialization¶
TeamListSerializerdepends on:request.user- Enables:
- per-user role resolution
- personalized responses
3. Lightweight vs rich responses¶
Two patterns are used:
Lightweight
- TeamMembershipPairSerializer
- Optimized for performance and mapping
Rich
- TeamMemberSerializer
- TeamMembershipListSerializer
- UI-friendly, detailed responses
4. No business logic in serializers¶
Serializers:
- ❌ Do not enforce permissions
- ❌ Do not modify database state
- ❌ Do not contain domain rules
They only: - validate input structure - format output - compute simple derived fields
All logic lives in:
- teams.services.*
5. Label normalization pattern¶
Consistent user labeling logic:
1. profile.display_name
2. full_name
3. email
4. fallback to username / ID
This ensures: - stable UI rendering - predictable identity display