Organizations App Reference¶
The Organizations app provides multi-tenant functionality with role-based access control (RBAC). Users can belong to multiple organizations, each with its own settings, members, and data. This app is the foundation that all other apps depend on for permission checks and data scoping.
Overview¶
Location: app/organizations/
Purpose: Multi-tenant organization management with RBAC
Key Models: Organization, OrganizationMembership, OrganizationInvitation, OrganizationSettings
Used By: All other apps depend on this app for permission checks, org-scoped data filtering, and permission mixins.
File Structure¶
organizations/
├── models.py # 4 models
├── views/ # Views package (3 modules)
│ ├── __init__.py # Re-exports all 16 views
│ ├── organization_views.py # 5 CBVs + 3 FBVs (CRUD, switching, settings)
│ ├── member_views.py # 3 FBVs (member list, remove, role change)
│ └── invitation_views.py # 5 FBVs (send, list, accept, decline, my)
├── forms.py # OrganizationSettingsForm
├── urls.py # 16 URL patterns
├── signals.py # Auto-create default org on user creation
├── middleware.py # OrganizationMiddleware + switch_organization()
├── utils.py # 11 permission utility functions
├── mixins.py # OrgPermissionMixin, DelegatedPermissionMixin
├── admin.py # Django admin config (4 model admins + 1 inline)
├── services/
│ ├── __init__.py
│ └── numbering_service.py # Charge/bucket numbering
└── templates/organizations/ # 13 HTML templates
Models¶
See Database Models - Organizations App for complete field reference.
Organization¶
Multi-tenant entity. Fields include name, org_type (personal/family/cooperative/commercial/club), description, logo (resized to 300x300px), and active status.
Key Methods:
get_owners()-- QuerySet of owner usersget_admins()-- QuerySet of admin and owner usersuser_is_member(user)-- booluser_role(user)-- role string or None
OrganizationMembership¶
User-Organization relationship with role-based access. Enforces a unique constraint on (organization, user).
Roles: owner, admin, member, viewer
Key Methods:
can_manage_members()-- owner/admin onlycan_delete_organization()-- owner onlycan_edit_resources()-- owner/admin/membercan_delete_resources()-- owner/admin only
OrganizationInvitation¶
Email invitation system with UUID tokens, 7-day expiration, and status tracking (pending/accepted/declined/expired).
Status Transitions: pending can move to accepted, declined, or expired. All three are terminal states.
Key Methods:
is_valid()-- checks if pending and not expired; auto-marks as expired if past expirationaccept(user)-- creates membership and marks as accepteddecline()-- marks as declinedeffective_status-- property that computes true status including implicit expiration
OrganizationSettings¶
Per-organization preferences: date format, timezone, unit system, language, branding colors (primary/secondary), MFA policy, email notification preferences, and charge/bucket numbering templates.
Middleware¶
OrganizationMiddleware¶
Location: app/organizations/middleware.py
Adds organization context to every request:
| Attribute | Description |
|---|---|
request.current_organization |
Active organization (or None for "all orgs" mode) |
request.user_organizations |
All user's organizations (QuerySet) |
request.org_colors |
Organization branding colors (dict with primary and secondary keys) |
Organization Selection Priority:
- Session variable
current_organization_id(user switched orgs or selected "all") - First organization by membership join date
- None (not authenticated)
When the session value is explicitly set to None, the user sees data from all their organizations. When the session variable is absent, the system defaults to the first organization.
switch_organization() -- Helper function to switch current organization via session. Pass None to switch to the "all organizations" view.
Permission Utilities¶
Location: app/organizations/utils.py
11 functions providing centralized permission checks:
get_user_role(user, organization) # Returns role or None
get_user_organizations(user) # Returns QuerySet
user_is_member(user, organization) # Returns bool
user_can_view(user, resource) # Returns bool
user_can_create(user, organization) # Returns bool
user_can_edit(user, resource) # Returns bool
user_can_delete(user, resource) # Returns bool
user_can_manage_members(user, organization) # Returns bool
user_can_delete_org(user, organization) # Returns bool
user_can_change_org_settings(user, org) # Returns bool
filter_by_user_organizations(queryset, user, request) # Returns filtered QuerySet
Permission Matrix:
| Action | Owner | Admin | Member | Viewer |
|---|---|---|---|---|
| View resources | Yes | Yes | Yes | Yes |
| Create resources | Yes | Yes | Yes | No |
| Edit own resources | Yes | Yes | Yes | No |
| Edit all resources | Yes | Yes | No | No |
| Delete resources | Yes | Yes | No | No |
| Manage members | Yes | Yes | No | No |
| Change settings | Yes | Yes | No | No |
| Delete organization | Yes | No | No | No |
See Permissions System for detailed documentation.
Permission Mixins¶
Location: app/organizations/mixins.py
OrgPermissionMixin¶
Reusable model mixin for organization-based permission checking. Add it to any model that has an organization ForeignKey and optionally a created_by field.
Methods:
user_can_view(user)-- any active organization member can viewuser_can_edit(user)-- admins/owners can edit all; members can edit own recordsuser_can_delete(user)-- only admins/owners can delete
Configuration: Set the permission_owner_field class attribute to the name of the field that stores the record creator (default: 'created_by').
Used by: QueenBreeding, ColonySplit, InventoryItem, InventoryTransaction, ProductSale, WarehouseLocation
DelegatedPermissionMixin¶
Mixin for child models that delegate permission checks to a parent model (e.g., status change records that inherit permissions from their parent entity).
Configuration: Set the permission_delegate_field class attribute to the name of the ForeignKey pointing to the parent.
Used by: BreedingStatusChange (delegates to breeding), SplitStatusChange (delegates to split)
Views¶
Organization CRUD¶
| View | Type | Purpose |
|---|---|---|
| OrganizationListView | CBV | List all orgs user belongs to, with member counts |
| OrganizationDetailView | CBV | Org details, members, hive/activity statistics |
| OrganizationCreateView | CBV | Create org, auto-create owner membership for creator |
| OrganizationUpdateView | CBV | Update org details (name, type, description, logo) |
| OrganizationDeleteView | CBV | Delete with cascade warning showing dependent data counts |
| switch_org_view | FBV | Switch to a different organization |
| switch_to_all_orgs_view | FBV | Switch to "all organizations" view |
| organization_settings_view | FBV | View and update organization settings |
Member Management¶
| View | Type | Purpose |
|---|---|---|
| member_list_view | FBV | List active members with roles |
| member_remove_view | FBV | Remove member (prevents self-removal and owner removal by non-owners) |
| member_role_change_view | FBV | Change member role (only owners can promote to owner) |
Invitation Management¶
| View | Type | Purpose |
|---|---|---|
| invitation_send_view | FBV | Send email invitation, validate duplicates and existing members |
| invitation_list_view | FBV | List all invitations for an organization |
| invitation_accept_view | FBV | Accept invitation, verify email match, create membership |
| invitation_decline_view | FBV | Decline invitation, verify email match |
| my_invitations_view | FBV | View valid pending invitations for current user |
Forms¶
OrganizationSettingsForm¶
Location: app/organizations/forms.py
Form for editing organization settings.
Fields: date_format, time_zone, unit_system, language, primary_color, secondary_color, email notification toggles, charge/bucket numbering format fields (including custom format inputs).
Widgets: HTML5 color pickers for branding colors, select dropdowns for numbering format, text inputs for custom numbering templates.
Validation: Custom charge and bucket format validation via NumberingValidator when the "custom" format option is selected.
Services¶
NumberingService¶
Location: app/organizations/services/numbering_service.py
Generates charge and bucket identifiers using configurable templates.
Key Methods:
generate_charge_identifier(organization, honey_type, harvest_year)-- returns strgenerate_bucket_number(organization, charge_identifier)-- returns str
Uses select_for_update() for thread-safe sequence incrementing.
Tokens: {YEAR}, {TYPE}, {LABEL}, {SEQ} for charges; {CHARGE}, {SEQ}, {EIMER}, {BUCKET} for buckets.
NumberingValidator¶
Validates custom numbering templates. Checks token existence, format specs, and uniqueness requirements.
Signals¶
create_default_organization¶
- Trigger:
post_saveon User (creation only) - Action: Auto-creates a personal organization named "{username}'s Beekeeping" with owner membership for every new user
- Purpose: Ensures all data belongs to an organization from the start
URL Patterns¶
organizations/ → OrganizationListView (organization-list)
organizations/create/ → OrganizationCreateView (organization-create)
organizations/<pk>/ → OrganizationDetailView (organization-detail)
organizations/<pk>/edit/ → OrganizationUpdateView (organization-update)
organizations/<pk>/delete/ → OrganizationDeleteView (organization-delete)
organizations/<pk>/switch/ → switch_org_view (organization-switch)
organizations/switch/all/ → switch_to_all_orgs_view (organization-switch-all)
organizations/<pk>/members/ → member_list_view (member-list)
organizations/<pk>/members/<user_id>/remove/ → member_remove_view (member-remove)
organizations/<pk>/members/<user_id>/change-role/ → member_role_change_view (member-role-change)
organizations/<pk>/invite/ → invitation_send_view (invitation-send)
organizations/<pk>/invitations/ → invitation_list_view (invitation-list)
organizations/invitations/accept/<token>/ → invitation_accept_view (invitation-accept)
organizations/invitations/decline/<token>/ → invitation_decline_view (invitation-decline)
organizations/my-invitations/ → my_invitations_view (my-invitations)
organizations/<pk>/settings/ → organization_settings_view (organization-settings)