Search App Reference¶
The Search app provides a unified search interface across all entity types in the Bifolk application. It uses an adapter pattern to search hives, queens, honey batches, inventory items, breeding records, and more from a single search bar.
Overview¶
Location: app/search/
Purpose: Global cross-entity search with live modal search and advanced filtering
Key Models: None (uses models from other apps via search adapters)
Dependencies: hives, breeding, warehouse, organizations
File Structure¶
search/
├── apps.py # AppConfig
├── forms.py # GlobalSearchForm, AdvancedSearchForm
├── views.py # SearchResultsView, search_api
├── urls.py # 2 URL patterns
├── services/
│ ├── __init__.py
│ ├── search_service.py # GlobalSearchService, PaginatedSearchResult
│ └── adapters/
│ ├── __init__.py # Re-exports all adapters
│ ├── base.py # BaseSearchAdapter, SearchResult
│ ├── hive_adapters.py # 7 adapters (Hive, Queen, HoneyBatch, HoneyBucket, HoneyJar, HiveInspection, HarvestRecord)
│ ├── warehouse_adapters.py # 3 adapters (InventoryItem, ProductSale, WarehouseLocation)
│ └── breeding_adapters.py # 2 adapters (QueenBreeding, ColonySplit)
├── templates/search/
│ ├── search_results.html # Full-page search results with filters
│ └── _search_modal.html # Global search modal (included in base template)
└── tests/
├── __init__.py
├── test_search_service.py # Service layer tests
├── test_adapters.py # Adapter tests
└── test_views.py # View tests
Views¶
SearchResultsView¶
Full-page search results view with advanced filtering.
- Location:
app/search/views.py:16 - Type: Class-based (TemplateView)
- Authentication: Required (LoginRequiredMixin)
- Template:
search/search_results.html - URL:
/search/(name:search:results)
Display Modes:
| Mode | Condition | Behavior |
|---|---|---|
| Grouped | No filters active | Results grouped by entity type, 20 per type |
| Flat | Filters active (entity type, org, date range) | Flat paginated list, 20 per page |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string | Search term (minimum 2 characters) |
entity_types |
list | Entity types to filter by |
organization |
integer | Organization ID to filter by |
date_from |
date | Start date filter (ISO format) |
date_to |
date | End date filter (ISO format) |
page |
integer | Page number for flat mode pagination |
The advanced search page always shows the organization filter regardless of the current site-wide organization selector, allowing users to search across all their organizations.
search_api(request)¶
JSON API endpoint for live search results, used by the search modal.
- Location:
app/search/views.py:153 - Type: Function-based view
- Authentication: Required (@login_required)
- URL:
/search/api/(name:search:api)
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string | Search term (minimum 2 characters) |
types |
string | Comma-separated entity types (optional) |
Response Format:
{
"results": {
"hive": [
{
"entity_type": "hive",
"entity_type_display": "Hive",
"id": 1,
"display_name": "Garden Hive",
"url": "/hives/1/",
"subtitle": "My Organization",
"context": "good",
"organization_name": "My Organization"
}
]
},
"total_count": 1,
"error": null
}
Forms¶
GlobalSearchForm¶
- Location:
app/search/forms.py:7 - Fields:
q(CharField, min_length=2, max_length=200) - Purpose: Simple search input used in the search modal
AdvancedSearchForm¶
- Location:
app/search/forms.py:24 - Purpose: Advanced search form with filtering options
Fields:
| Field | Type | Description |
|---|---|---|
q |
CharField | Search query (min 2, max 200 characters) |
entity_types |
MultipleChoiceField | Entity type checkboxes (dynamic choices) |
organization |
ChoiceField | Organization dropdown (dynamic, hidden if only one org) |
date_from |
DateField | Start date filter |
date_to |
DateField | End date filter |
Constructor Parameters:
| Parameter | Purpose |
|---|---|
user |
Populate organization choices from user memberships |
current_organization |
If set, hides organization field |
entity_type_choices |
List of (value, label) tuples for entity types |
Validation: Ensures date_from is before date_to when both are provided.
Services¶
GlobalSearchService¶
Location: app/search/services/search_service.py:41
Orchestrates searching across all registered search adapters. Coordinates 12 adapters and aggregates results.
Configuration:
| Property | Value |
|---|---|
MIN_QUERY_LENGTH |
2 |
ADAPTERS |
12 registered adapters (see Adapter Registry below) |
Methods:
| Method | Purpose | Returns |
|---|---|---|
search(search_term, user, ...) |
Search grouped by entity type | dict[str, list[SearchResult]] |
search_flat(search_term, user, ...) |
Search as flat list | list[SearchResult] |
search_paginated(search_term, user, ..., page, per_page) |
Search with pagination | PaginatedSearchResult |
get_available_entity_types() |
List all entity types with display names | list[dict] |
get_entity_type_choices() |
Entity types as form choices | list[tuple[str, str]] |
All search methods accept these common parameters:
| Parameter | Type | Description |
|---|---|---|
search_term |
str | Search query (minimum 2 characters) |
user |
User | The requesting user |
request |
HttpRequest (optional) | For current organization context |
entity_types |
list[str] (optional) | Filter by entity types |
date_from |
date (optional) | Start date filter |
date_to |
date (optional) | End date filter |
organization_id |
int (optional) | Filter by specific organization |
PaginatedSearchResult¶
Location: app/search/services/search_service.py:27
Dataclass for paginated search results.
Fields:
| Field | Type | Description |
|---|---|---|
results |
list[SearchResult] | Results for current page |
total_count |
int | Total results across all pages |
page |
int | Current page number |
per_page |
int | Results per page |
total_pages |
int | Total number of pages |
has_next |
bool | Whether a next page exists |
has_previous |
bool | Whether a previous page exists |
Search Adapters¶
The search app uses an adapter pattern where each adapter is responsible for searching a single model type and returning standardized SearchResult objects.
BaseSearchAdapter¶
Location: app/search/services/adapters/base.py:56
Abstract base class that all search adapters must extend.
Required Overrides:
| Method | Purpose |
|---|---|
get_model() |
Return the model class to search |
get_entity_type_display() |
Return translated display name |
get_search_q(search_term) |
Return Q object for search filtering |
result_to_search_result(obj) |
Convert model instance to SearchResult |
Optional Overrides:
| Method | Purpose |
|---|---|
get_base_queryset(user, request) |
Custom organization filtering (default: select_related('organization') + filter_by_user_organizations) |
apply_organization_filter(queryset, organization_id) |
Custom org filter (default: organization_id=organization_id) |
apply_date_filter(queryset, date_from, date_to) |
Custom date filtering (default: uses primary_date_field) |
Properties:
| Property | Default | Purpose |
|---|---|---|
entity_type |
'' |
Internal identifier (e.g., 'hive') |
default_limit |
10 |
Maximum results per search |
primary_date_field |
'created_at' |
Field used for date range filtering |
SearchResult¶
Location: app/search/services/adapters/base.py:18
Standardized dataclass for search results.
Fields:
| Field | Type | Default | Description |
|---|---|---|---|
entity_type |
str | (required) | Internal type identifier |
entity_type_display |
str | (required) | Translated display name |
id |
int | (required) | Primary key of matched entity |
display_name |
str | (required) | Main display text |
url |
str | (required) | URL to entity detail view |
subtitle |
str | '' |
Secondary text (location, status) |
context |
str | '' |
Status indicator (good, warning, etc.) |
organization_name |
str | '' |
Organization name |
Adapter Registry¶
All 12 registered adapters, organized by source app:
Hive Adapters (services/adapters/hive_adapters.py):
| Adapter | Entity Type | Default Limit | Date Field | Searchable Fields |
|---|---|---|---|---|
HiveSearchAdapter |
hive |
10 | installation_date |
name, display_name, notes |
QueenSearchAdapter |
queen |
10 | created_at |
breed, identification_number, breeder_name, notes |
HoneyBatchSearchAdapter |
honey_batch |
5 | created_date |
charge_identifier, notes |
HoneyBucketSearchAdapter |
honey_bucket |
5 | created_at |
bucket_number, notes |
HoneyJarSearchAdapter |
honey_jar |
5 | created_at |
jar_number, notes |
HiveInspectionSearchAdapter |
hive_inspection |
5 | inspection_date |
notes, disease_notes, pest_notes |
HarvestRecordSearchAdapter |
harvest_record |
5 | harvest_date |
notes |
Warehouse Adapters (services/adapters/warehouse_adapters.py):
| Adapter | Entity Type | Default Limit | Date Field | Searchable Fields |
|---|---|---|---|---|
InventoryItemSearchAdapter |
inventory_item |
10 | created_at |
name, item_type, description |
ProductSaleSearchAdapter |
product_sale |
5 | sale_date |
customer_name, notes |
WarehouseLocationSearchAdapter |
warehouse_location |
5 | created_at |
name, description |
Breeding Adapters (services/adapters/breeding_adapters.py):
| Adapter | Entity Type | Default Limit | Date Field | Searchable Fields |
|---|---|---|---|---|
QueenBreedingSearchAdapter |
queen_breeding |
5 | breeding_date |
breed_line, notes, drone_source |
ColonySplitSearchAdapter |
colony_split |
5 | split_date |
notes |
Custom Organization Filtering¶
Some adapters override get_base_queryset and apply_organization_filter because their models do not have a direct organization field:
| Adapter | Organization Path |
|---|---|
HoneyBucketSearchAdapter |
batch__organization |
HoneyJarSearchAdapter |
bucket__batch__organization |
HiveInspectionSearchAdapter |
hive__organization |
HarvestRecordSearchAdapter |
organization (direct, with prefetch of hives) |
Templates¶
search_results.html¶
Full-page search results template. Includes:
- Search input with submit button
- Collapsible filter panel (entity type checkboxes, organization dropdown, date range)
- Select All / Clear All buttons for entity type checkboxes
- Grouped results view (cards by entity type with icon per type)
- Flat results view with pagination
- Status badges with color-coded context (good/warning/critical)
- Empty state and minimum character length messages
_search_modal.html¶
Global search modal included in the base template. Features:
- Large search input with keyboard hint (Esc to close)
- Loading spinner
- Empty state and no-results messages
- Dynamic results container (populated via JavaScript and the search API)
- Keyboard navigation hints (arrow keys, Enter)
- Link to advanced search page
URL Configuration¶
| URL | View | Name |
|---|---|---|
/search/ |
SearchResultsView |
search:results |
/search/api/ |
search_api |
search:api |
Key Features¶
- Unified Search: Search across 12 entity types from a single input
- Adapter Pattern: Each model type has its own adapter for customized search behavior
- Live Search Modal: Real-time search results via JSON API as the user types
- Advanced Filtering: Filter by entity type, organization, and date range
- Two Display Modes: Grouped by entity type (no filters) or flat paginated list (with filters)
- Organization-Aware: Results filtered by user's accessible organizations
- Cross-Organization Search: Advanced search ignores site-wide org selector, searches all user orgs
- Minimum Query Length: Requires at least 2 characters to prevent overly broad searches
- Keyboard Navigation: Modal supports arrow key navigation and Enter to open
See Also¶
- Hives App - Hive, Queen, Batch, Inspection models searched by this app
- Warehouse App - Inventory, Sale, Location models searched by this app
- Breeding App - QueenBreeding, ColonySplit models searched by this app
- Organizations App - Organization filtering used by all adapters