SystemConfig App Reference¶
The SystemConfig app provides database-driven configurable dropdown choices for forms, allowing administrators to customize options without code changes. Choices are organization-specific with utility functions, login validation, template filters, and deletion protection.
Overview¶
Location: app/systemconfig/
Purpose: Configurable dropdown choices with utility functions and login validation
URL Namespace: /system/
Key Models: ChoiceCategory, ConfigurableChoice
Used By: Hives (hive styles, honey types, operation types), Breeding (methods, statuses), Warehouse (item types, units, payment methods), Organizations (settings form)
File Structure¶
systemconfig/
├── models.py # 2 models (ChoiceCategory, ConfigurableChoice)
├── views.py # 6 view classes + 1 permission mixin
├── forms.py # ConfigurableChoiceForm
├── urls.py # 6 URL patterns
├── utils.py # 8 utility functions for forms/views
├── services.py # Login validation service
├── signals.py # 1 signal handler (user_logged_in)
├── apps.py # AppConfig with post_migrate auto-category creation
├── admin.py # Admin with inline editing + bulk delete protection
├── templatetags/
│ └── choice_filters.py # 2 template filters (get_choice_display, translate)
├── management/commands/
│ └── load_default_categories.py # CLI to load default categories + choices
├── tests/ # Model, view, signal, and service tests
└── templates/systemconfig/
├── category_list.html
├── choice_list.html
├── choice_form.html
└── choice_confirm_delete.html
Models¶
See Database Models - SystemConfig App for complete field reference.
ChoiceCategory¶
Represents a configurable category (e.g., "Hive Style", "Honey Type").
Fields: name, code (unique slug), description, order, is_active, created_at, updated_at
27 Default Categories (auto-created via post_migrate signal in apps.py):
honey_type, hive_style, health_status, queen_origin, temperament, inspection_status, drone_presence, operation_status, operation_priority, feed_type, treatment_type, treatment_effectiveness, breeding_method, breeding_status, breeding_quality, combine_method, split_type, split_status, queen_replacement_method, queen_replacement_reason, maintenance_type, unit_type, equipment_type, supply_type, product_type, payment_method, transaction_type
Note: queen_marking_color is no longer configurable; it uses a fixed set of choices (White, Yellow, Red, Green, Blue, Unmarked) following the international beekeeping standard.
ConfigurableChoice¶
Individual choices within a category, belonging to a specific organization.
Fields: category (FK), organization (FK, nullable), label, value (auto-slug from label, not editable), description, order, is_active, is_default, brood_chamber_weight_kg, honey_chamber_weight_kg, honeycomb_weight_kg, created_at, updated_at
Constraint: Unique (category, value, organization)
Key Methods:
- can_be_deleted() -- Checks all reverse FK relations with on_delete=PROTECT; returns (bool, blocking_objects_list)
- delete() -- Overridden to call can_be_deleted() first; raises ValidationError if referenced
Save Hook: Auto-generates value slug from label with uniqueness check. When is_default=True, clears the default flag from other choices in the same category/organization scope.
Organization-Specific Choices¶
All choices belong to a specific organization. The organization field is required for non-staff users.
When querying choices for a form, use the utility functions which handle organization filtering:
from systemconfig.utils import populate_choice_field
# In a form's __init__ method:
populate_choice_field(
self, 'feed_type', 'feed_type',
organization=current_org
)
Views¶
OrganizationManagerOrStaffMixin¶
Permission control mixin restricting access to staff, org owners, and org admins. Includes user_can_edit_choice() for per-choice permission checks.
CRUD Views¶
| View | Purpose |
|---|---|
| CategoryListView | List active categories with choice counts per organization |
| ChoiceListView | List choices for a category with sorting (SortableListMixin) |
| ChoiceCreateView | Create new choice with category from URL |
| ChoiceUpdateView | Update choice with per-choice permission check |
| ChoiceDeleteView | Delete choice; shows blocking objects if referenced |
| LoadDefaultCategoriesView | POST-only; loads default categories and choices |
Forms¶
ConfigurableChoiceForm¶
Fields: label, description, order, is_active, is_default, brood_chamber_weight_kg, honey_chamber_weight_kg, honeycomb_weight_kg, organization
Conditional Fields: Chamber weight fields (brood, honey, honeycomb) are hidden when category is not hive_style.
Dynamic Organization Field:
- Superusers: Required, can select any organization
- Org owners/admins (multiple orgs): Required dropdown of managed organizations
- Org owners/admins (single org): Hidden, auto-set to managed organization
Validation: clean_organization() ensures the user has owner/admin role for the selected organization.
URL Patterns¶
system/ -> CategoryListView (systemconfig-home)
system/load-defaults/ -> LoadDefaultCategoriesView (systemconfig-load-defaults)
system/<slug:category_code>/ -> ChoiceListView (systemconfig-choice-list)
system/<slug:category_code>/new/ -> ChoiceCreateView (systemconfig-choice-create)
system/choice/<int:pk>/edit/ -> ChoiceUpdateView (systemconfig-choice-update)
system/choice/<int:pk>/delete/ -> ChoiceDeleteView (systemconfig-choice-delete)
Utility Functions¶
The utils.py module provides helper functions for forms and views:
| Function | Purpose |
|---|---|
get_queryset_for_category() |
QuerySet of choices for ModelChoiceField |
get_default_choice() |
Get the default choice for a category |
get_choice_value() |
Get slug value by primary key |
get_choice_by_value() |
Reverse lookup: find choice by category and value |
validate_choice_value() |
Check if a value exists in a category |
category_exists() |
Check if an active category exists |
get_choices_for_category() |
Tuple list for ChoiceField with warnings for empty categories |
populate_choice_field() |
Set field choices and add configuration link to help text |
get_config_link_help_text() |
Generate HTML link to the configuration page |
add_config_link_help_text() |
Append configuration link to a field's help text |
Usage in Forms¶
from systemconfig.utils import populate_choice_field
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
organization = kwargs.pop('organization', None)
super().__init__(*args, **kwargs)
# Populate field with choices and add config link
populate_choice_field(
self, 'unit', 'unit_type',
organization=organization,
include_blank=True,
blank_label=_('Select unit')
)
Services¶
Login Validation¶
On user login, the system checks all active categories for missing configuration:
validate_system_categories_for_user(user)-- Checks orgs where user is owner/admin- Creates system notifications for unconfigured categories
- Uses 24-hour deduplication to prevent repeated notifications
Signals¶
handle_user_logged_in¶
- Trigger:
user_logged_insignal - Action: Calls
validate_system_categories_for_user() - Error handling: All exceptions caught and logged; never blocks login
Template Tags¶
Two template filters in templatetags/choice_filters.py:
| Filter | Usage | Purpose |
|---|---|---|
get_choice_display |
{{ value\|get_choice_display:"category_code" }} |
Look up display label for a stored value |
translate |
{{ category.name\|translate }} |
Apply Django translation to database strings |
Management Commands¶
load_default_categories¶
Load default choice categories and sample choices:
Delegates to the sample data service. Safe to run multiple times (uses get_or_create).
When to Use ConfigurableChoice¶
Use ConfigurableChoice when:
- Options should be user-customizable
- Organizations need different options
- The list of options may grow over time
- No code logic depends on specific values
Use hardcoded choices when:
- Options are fixed (e.g., yes/no, status values)
- Code branches based on values
- Only 2-3 options exist
- Performance is critical (avoids extra queries)
See Also¶
- Database Models - SystemConfig
- Admin Guide - System Configuration
- Hives App Reference - Uses configurable choices for hive types